source: mainline/uspace/lib/ext4/src/superblock.c@ b209135

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

Reading volume label from ext4 file system.

  • Property mode set to 100644
File size: 37.5 KB
RevLine 
[eb91db7]1/*
[aab85d90]2 * Copyright (c) 2018 Jiri Svoboda
[d1538a1]3 * Copyright (c) 2011 Martin Sucha
[f22d5ef0]4 * Copyright (c) 2012 Frantisek Princ
[eb91db7]5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/** @addtogroup libext4
32 * @{
[38542dc]33 */
[eb91db7]34
35/**
[4bfad34]36 * @file superblock.c
[38542dc]37 * @brief Ext4 superblock operations.
[eb91db7]38 */
39
[aab85d90]40#include <align.h>
[fcb0d76]41#include <block.h>
[01ab41b]42#include <byteorder.h>
43#include <errno.h>
[fcb0d76]44#include <mem.h>
[38d150e]45#include <stdlib.h>
[b209135]46#include <str.h>
[aab85d90]47#include <time.h>
[2175178]48#include "ext4/cfg.h"
[fcb0d76]49#include "ext4/superblock.h"
[eb91db7]50
[9fc72fb3]51/** Get number of i-nodes in the whole filesystem.
52 *
[38542dc]53 * @param sb Superblock
54 *
55 * @return Number of i-nodes
56 *
[9fc72fb3]57 */
[3712434]58uint32_t ext4_superblock_get_inodes_count(ext4_superblock_t *sb)
[01ab41b]59{
[3712434]60 return uint32_t_le2host(sb->inodes_count);
[01ab41b]61}
62
[9fc72fb3]63/** Set number of i-nodes in the whole filesystem.
64 *
[38542dc]65 * @param sb Superblock
66 * @param count Number of i-nodes
67 *
[9fc72fb3]68 */
[fe27eb4]69void ext4_superblock_set_inodes_count(ext4_superblock_t *sb, uint32_t count)
70{
71 sb->inodes_count = host2uint32_t_le(count);
72}
73
[9fc72fb3]74/** Get number of data blocks in the whole filesystem.
75 *
[38542dc]76 * @param sb Superblock
77 *
78 * @return Number of data blocks
79 *
[9fc72fb3]80 */
[3712434]81uint64_t ext4_superblock_get_blocks_count(ext4_superblock_t *sb)
82{
[38542dc]83 return ((uint64_t) uint32_t_le2host(sb->blocks_count_hi) << 32) |
84 uint32_t_le2host(sb->blocks_count_lo);
[3712434]85}
86
[9fc72fb3]87/** Set number of data blocks in the whole filesystem.
88 *
[38542dc]89 * @param sb Superblock
90 * @param count Number of data blocks
91 *
[9fc72fb3]92 */
[fe27eb4]93void ext4_superblock_set_blocks_count(ext4_superblock_t *sb, uint64_t count)
94{
95 sb->blocks_count_lo = host2uint32_t_le((count << 32) >> 32);
96 sb->blocks_count_hi = host2uint32_t_le(count >> 32);
97}
98
[9fc72fb3]99/** Get number of reserved data blocks in the whole filesystem.
100 *
[38542dc]101 * @param sb Superblock
102 *
103 * @return Number of reserved data blocks
104 *
[9fc72fb3]105 */
[3712434]106uint64_t ext4_superblock_get_reserved_blocks_count(ext4_superblock_t *sb)
107{
[38542dc]108 return ((uint64_t)
109 uint32_t_le2host(sb->reserved_blocks_count_hi) << 32) |
110 uint32_t_le2host(sb->reserved_blocks_count_lo);
[3712434]111}
112
[9fc72fb3]113/** Set number of reserved data blocks in the whole filesystem.
114 *
[38542dc]115 * @param sb Superblock
116 * @param count Number of reserved data blocks
117 *
[9fc72fb3]118 */
[38542dc]119void ext4_superblock_set_reserved_blocks_count(ext4_superblock_t *sb,
120 uint64_t count)
[fe27eb4]121{
122 sb->reserved_blocks_count_lo = host2uint32_t_le((count << 32) >> 32);
123 sb->reserved_blocks_count_hi = host2uint32_t_le(count >> 32);
124}
125
[9fc72fb3]126/** Get number of free data blocks in the whole filesystem.
127 *
[38542dc]128 * @param sb Superblock
129 *
130 * @return Number of free data blocks
131 *
[9fc72fb3]132 */
[3712434]133uint64_t ext4_superblock_get_free_blocks_count(ext4_superblock_t *sb)
134{
[38542dc]135 return ((uint64_t)
136 uint32_t_le2host(sb->free_blocks_count_hi) << 32) |
137 uint32_t_le2host(sb->free_blocks_count_lo);
[3712434]138}
139
[9fc72fb3]140/** Set number of free data blocks in the whole filesystem.
141 *
[38542dc]142 * @param sb Superblock
143 * @param count Number of free data blocks
144 *
[9fc72fb3]145 */
[38542dc]146void ext4_superblock_set_free_blocks_count(ext4_superblock_t *sb,
147 uint64_t count)
[ae3d4f8]148{
149 sb->free_blocks_count_lo = host2uint32_t_le((count << 32) >> 32);
150 sb->free_blocks_count_hi = host2uint32_t_le(count >> 32);
151}
152
[9fc72fb3]153/** Get number of free i-nodes in the whole filesystem.
154 *
[38542dc]155 * @param sb Superblock
156 *
157 * @return Number of free i-nodes
158 *
[9fc72fb3]159 */
[3712434]160uint32_t ext4_superblock_get_free_inodes_count(ext4_superblock_t *sb)
161{
162 return uint32_t_le2host(sb->free_inodes_count);
163}
164
[9fc72fb3]165/** Set number of free i-nodes in the whole filesystem.
166 *
[38542dc]167 * @param sb Superblock
168 * @param count Number of free i-nodes
169 *
[9fc72fb3]170 */
[38542dc]171void ext4_superblock_set_free_inodes_count(ext4_superblock_t *sb,
172 uint32_t count)
[fe27eb4]173{
174 sb->free_inodes_count = host2uint32_t_le(count);
175}
176
[38542dc]177/** Get index of first data block (block where the superblock is located)
178 *
179 * @param sb Superblock
180 *
181 * @return Index of the first data block
[9fc72fb3]182 *
183 */
[3712434]184uint32_t ext4_superblock_get_first_data_block(ext4_superblock_t *sb)
[01ab41b]185{
[9c0c0e1]186 return uint32_t_le2host(sb->first_data_block);
[01ab41b]187}
188
[38542dc]189/** Set index of first data block (block where the superblock is located)
190 *
191 * @param sb Superblock
192 * @param first Index of the first data block
[9fc72fb3]193 *
194 */
[38542dc]195void ext4_superblock_set_first_data_block(ext4_superblock_t *sb,
196 uint32_t first)
[fe27eb4]197{
198 sb->first_data_block = host2uint32_t_le(first);
199}
200
[9fc72fb3]201/** Get logarithmic block size (1024 << size == block_size)
202 *
[38542dc]203 * @param sb Superblock
204 *
205 * @return Logarithmic block size
206 *
[9fc72fb3]207 */
[3712434]208uint32_t ext4_superblock_get_log_block_size(ext4_superblock_t *sb)
[01ab41b]209{
[9c0c0e1]210 return uint32_t_le2host(sb->log_block_size);
[01ab41b]211}
212
[9fc72fb3]213/** Set logarithmic block size (1024 << size == block_size)
214 *
[38542dc]215 * @param sb Superblock
216 *
217 * @return Logarithmic block size
218 *
[9fc72fb3]219 */
[38542dc]220void ext4_superblock_set_log_block_size(ext4_superblock_t *sb,
221 uint32_t log_size)
[fe27eb4]222{
223 sb->log_block_size = host2uint32_t_le(log_size);
224}
225
[9fc72fb3]226/** Get size of data block (in bytes).
227 *
[38542dc]228 * @param sb Superblock
229 *
230 * @return Size of data block
231 *
[9fc72fb3]232 */
[01ab41b]233uint32_t ext4_superblock_get_block_size(ext4_superblock_t *sb)
234{
[3712434]235 return 1024 << ext4_superblock_get_log_block_size(sb);
236}
237
[9fc72fb3]238/** Set size of data block (in bytes).
239 *
[38542dc]240 * @param sb Superblock
241 * @param size Size of data block (must be power of 2, at least 1024)
242 *
[9fc72fb3]243 */
[fe27eb4]244void ext4_superblock_set_block_size(ext4_superblock_t *sb, uint32_t size)
245{
246 uint32_t log = 0;
247 uint32_t tmp = size / EXT4_MIN_BLOCK_SIZE;
[a35b458]248
[fe27eb4]249 tmp >>= 1;
250 while (tmp) {
251 log++;
252 tmp >>= 1;
253 }
[a35b458]254
[fe27eb4]255 ext4_superblock_set_log_block_size(sb, log);
256}
[3712434]257
[fb04cd90]258/** Get logarithmic fragment size (1024 << size)
259 *
[38542dc]260 * @param sb Superblock
261 *
262 * @return Logarithmic fragment size
263 *
[fb04cd90]264 */
265uint32_t ext4_superblock_get_log_frag_size(ext4_superblock_t *sb)
266{
267 return uint32_t_le2host(sb->log_frag_size);
268}
269
270/** Set logarithmic fragment size (1024 << size)
271 *
[38542dc]272 * @param sb Superblock
273 * @param frag_size Logarithmic fragment size
274 *
[fb04cd90]275 */
[38542dc]276void ext4_superblock_set_log_frag_size(ext4_superblock_t *sb,
277 uint32_t frag_size)
[fb04cd90]278{
279 sb->log_frag_size = host2uint32_t_le(frag_size);
280}
281
282/** Get size of fragment (in bytes).
283 *
[38542dc]284 * @param sb Superblock
285 *
286 * @return Size of fragment
287 *
[fb04cd90]288 */
289uint32_t ext4_superblock_get_frag_size(ext4_superblock_t *sb)
290{
291 return 1024 << ext4_superblock_get_log_frag_size(sb);
292}
293
294/** Set size of fragment (in bytes).
295 *
[38542dc]296 * @param sb Superblock
297 * @param size Size of fragment (must be power of 2, at least 1024)
298 *
[fb04cd90]299 */
300void ext4_superblock_set_frag_size(ext4_superblock_t *sb, uint32_t size)
301{
302 uint32_t log = 0;
303 uint32_t tmp = size / EXT4_MIN_BLOCK_SIZE;
[a35b458]304
[fb04cd90]305 tmp >>= 1;
306 while (tmp) {
307 log++;
308 tmp >>= 1;
309 }
[a35b458]310
[fb04cd90]311 ext4_superblock_set_log_frag_size(sb, log);
312}
313
[9fc72fb3]314/** Get number of data blocks per block group (except last BG)
315 *
[38542dc]316 * @param sb Superblock
317 *
318 * @return Data blocks per block group
319 *
[9fc72fb3]320 */
[3712434]321uint32_t ext4_superblock_get_blocks_per_group(ext4_superblock_t *sb)
322{
323 return uint32_t_le2host(sb->blocks_per_group);
324}
325
[9fc72fb3]326/** Set number of data blocks per block group (except last BG)
327 *
[38542dc]328 * @param sb Superblock
329 * @param blocks Data blocks per block group
330 *
[9fc72fb3]331 */
[38542dc]332void ext4_superblock_set_blocks_per_group(ext4_superblock_t *sb,
333 uint32_t blocks)
[fe27eb4]334{
335 sb->blocks_per_group = host2uint32_t_le(blocks);
336}
337
[fb04cd90]338/** Get number of fragments per block group (except last BG)
339 *
[38542dc]340 * @param sb Superblock
341 *
342 * @return Fragments per block group
343 *
[fb04cd90]344 */
345uint32_t ext4_superblock_get_frags_per_group(ext4_superblock_t *sb)
346{
347 return uint32_t_le2host(sb->frags_per_group);
348}
349
350/** Set number of fragment per block group (except last BG)
351 *
[38542dc]352 * @param sb Superblock
353 * @param frags Fragments per block group
[fb04cd90]354 */
355void ext4_superblock_set_frags_per_group(ext4_superblock_t *sb, uint32_t frags)
356{
357 sb->frags_per_group = host2uint32_t_le(frags);
358}
359
[9fc72fb3]360/** Get number of i-nodes per block group (except last BG)
361 *
[38542dc]362 * @param sb Superblock
363 *
364 * @return I-nodes per block group
365 *
[9fc72fb3]366 */
[3712434]367uint32_t ext4_superblock_get_inodes_per_group(ext4_superblock_t *sb)
368{
369 return uint32_t_le2host(sb->inodes_per_group);
370}
371
[9fc72fb3]372/** Set number of i-nodes per block group (except last BG)
373 *
[38542dc]374 * @param sb Superblock
375 * @param inodes I-nodes per block group
376 *
[9fc72fb3]377 */
[38542dc]378void ext4_superblock_set_inodes_per_group(ext4_superblock_t *sb,
379 uint32_t inodes)
[fe27eb4]380{
381 sb->inodes_per_group = host2uint32_t_le(inodes);
382}
383
[9fc72fb3]384/** Get time when filesystem was mounted (POSIX time).
385 *
[38542dc]386 * @param sb Superblock
387 *
388 * @return Mount time
389 *
[9fc72fb3]390 */
[3712434]391uint32_t ext4_superblock_get_mount_time(ext4_superblock_t *sb)
392{
393 return uint32_t_le2host(sb->mount_time);
394}
395
[9fc72fb3]396/** Set time when filesystem was mounted (POSIX time).
397 *
[38542dc]398 * @param sb Superblock
399 * @param time Mount time
400 *
[9fc72fb3]401 */
[fe27eb4]402void ext4_superblock_set_mount_time(ext4_superblock_t *sb, uint32_t time)
403{
404 sb->mount_time = host2uint32_t_le(time);
405}
406
[9fc72fb3]407/** Get time when filesystem was last accesed by write operation (POSIX time).
408 *
[38542dc]409 * @param sb Superblock
410 *
411 * @return Write time
412 *
[9fc72fb3]413 */
[3712434]414uint32_t ext4_superblock_get_write_time(ext4_superblock_t *sb)
415{
416 return uint32_t_le2host(sb->write_time);
417}
418
[9fc72fb3]419/** Set time when filesystem was last accesed by write operation (POSIX time).
420 *
[38542dc]421 * @param sb Superblock
422 * @param time Write time
423 *
[9fc72fb3]424 */
[fe27eb4]425void ext4_superblock_set_write_time(ext4_superblock_t *sb, uint32_t time)
426{
427 sb->write_time = host2uint32_t_le(time);
428}
429
[9fc72fb3]430/** Get number of mount from last filesystem check.
431 *
[38542dc]432 * @param sb Superblock
433 *
434 * @return Number of mounts
435 *
[9fc72fb3]436 */
[3712434]437uint16_t ext4_superblock_get_mount_count(ext4_superblock_t *sb)
438{
439 return uint16_t_le2host(sb->mount_count);
440}
441
[9fc72fb3]442/** Set number of mount from last filesystem check.
443 *
[38542dc]444 * @param sb Superblock
445 * @param count Number of mounts
446 *
[9fc72fb3]447 */
[fe27eb4]448void ext4_superblock_set_mount_count(ext4_superblock_t *sb, uint16_t count)
449{
450 sb->mount_count = host2uint16_t_le(count);
451}
452
[9fc72fb3]453/** Get maximum number of mount from last filesystem check.
454 *
[38542dc]455 * @param sb Superblock
456 *
457 * @return Maximum number of mounts
458 *
[9fc72fb3]459 */
[3712434]460uint16_t ext4_superblock_get_max_mount_count(ext4_superblock_t *sb)
461{
462 return uint16_t_le2host(sb->max_mount_count);
463}
464
[9fc72fb3]465/** Set maximum number of mount from last filesystem check.
466 *
[38542dc]467 * @param sb Superblock
468 * @param count Maximum number of mounts
469 *
[9fc72fb3]470 */
[fe27eb4]471void ext4_superblock_set_max_mount_count(ext4_superblock_t *sb, uint16_t count)
472{
473 sb->max_mount_count = host2uint16_t_le(count);
474}
475
[9fc72fb3]476/** Get superblock magic value.
477 *
[38542dc]478 * @param sb Superblock
479 *
480 * @return Magic value
481 *
[9fc72fb3]482 */
[3712434]483uint16_t ext4_superblock_get_magic(ext4_superblock_t *sb)
484{
485 return uint16_t_le2host(sb->magic);
486}
487
[9fc72fb3]488/** Set superblock magic value.
489 *
[38542dc]490 * @param sb Superblock
491 * @param magic Magic value
492 *
[9fc72fb3]493 */
494void ext4_superblock_set_magic(ext4_superblock_t *sb, uint16_t magic)
495{
496 sb->magic = host2uint16_t_le(magic);
497}
498
[2226cc3]499/** Get filesystem state.
[9fc72fb3]500 *
[38542dc]501 * @param sb Superblock
502 *
503 * @return Filesystem state
504 *
[9fc72fb3]505 */
[3712434]506uint16_t ext4_superblock_get_state(ext4_superblock_t *sb)
507{
508 return uint16_t_le2host(sb->state);
509}
510
[2226cc3]511/** Set filesystem state.
[9fc72fb3]512 *
[38542dc]513 * @param sb Superblock
514 * @param state Filesystem state
515 *
[9fc72fb3]516 */
[fe27eb4]517void ext4_superblock_set_state(ext4_superblock_t *sb, uint16_t state)
518{
519 sb->state = host2uint16_t_le(state);
520}
521
[2226cc3]522/** Get behavior code when errors detected.
[9fc72fb3]523 *
[38542dc]524 * @param sb Superblock
525 *
526 * @return Behavior code
527 *
[9fc72fb3]528 */
[3712434]529uint16_t ext4_superblock_get_errors(ext4_superblock_t *sb)
530{
531 return uint16_t_le2host(sb->errors);
532}
533
[2226cc3]534/** Set behavior code when errors detected.
[9fc72fb3]535 *
[38542dc]536 * @param sb Superblock
537 * @param errors Behavior code
538 *
[9fc72fb3]539 */
[fe27eb4]540void ext4_superblock_set_errors(ext4_superblock_t *sb, uint16_t errors)
541{
542 sb->errors = host2uint16_t_le(errors);
543}
[3712434]544
[2226cc3]545/** Get minor revision level of the filesystem.
[9fc72fb3]546 *
[38542dc]547 * @param sb Superblock
548 *
549 * @return Minor revision level
550 *
[9fc72fb3]551 */
[3712434]552uint16_t ext4_superblock_get_minor_rev_level(ext4_superblock_t *sb)
553{
554 return uint16_t_le2host(sb->minor_rev_level);
555}
556
[2226cc3]557/** Set minor revision level of the filesystem.
[9fc72fb3]558 *
[38542dc]559 * @param sb Superblock
560 * @param level Minor revision level
561 *
[9fc72fb3]562 */
[fe27eb4]563void ext4_superblock_set_minor_rev_level(ext4_superblock_t *sb, uint16_t level)
564{
565 sb->minor_rev_level = host2uint16_t_le(level);
566}
567
[2226cc3]568/** Get time of the last filesystem check.
[9fc72fb3]569 *
[38542dc]570 * @param sb Superblock
571 *
572 * @return Time of the last check (POSIX)
573 *
[9fc72fb3]574 */
[3712434]575uint32_t ext4_superblock_get_last_check_time(ext4_superblock_t *sb)
576{
577 return uint32_t_le2host(sb->last_check_time);
578}
579
[2226cc3]580/** Set time of the last filesystem check.
[9fc72fb3]581 *
[38542dc]582 * @param sb Superblock
583 * @param time Time of the last check (POSIX)
584 *
[9fc72fb3]585 */
[fe27eb4]586void ext4_superblock_set_last_check_time(ext4_superblock_t *sb, uint32_t time)
587{
[aab85d90]588 sb->last_check_time = host2uint32_t_le(time);
[fe27eb4]589}
590
[2226cc3]591/** Get maximum time interval between two filesystem checks.
[9fc72fb3]592 *
[38542dc]593 * @param sb Superblock
594 *
595 * @return Time interval between two check (POSIX)
596 *
[9fc72fb3]597 */
[38542dc]598uint32_t ext4_superblock_get_check_interval(ext4_superblock_t *sb)
599{
[3712434]600 return uint32_t_le2host(sb->check_interval);
601}
602
[2226cc3]603/** Set maximum time interval between two filesystem checks.
[9fc72fb3]604 *
[38542dc]605 * @param sb Superblock
606 * @param interval Time interval between two check (POSIX)
607 *
[9fc72fb3]608 */
[fe27eb4]609void ext4_superblock_set_check_interval(ext4_superblock_t *sb, uint32_t interval)
610{
611 sb->check_interval = host2uint32_t_le(interval);
612}
613
[2226cc3]614/** Get operation system identifier, on which the filesystem was created.
[9fc72fb3]615 *
[38542dc]616 * @param sb Superblock
617 *
618 * @return Operation system identifier
619 *
[9fc72fb3]620 */
[3712434]621uint32_t ext4_superblock_get_creator_os(ext4_superblock_t *sb)
622{
623 return uint32_t_le2host(sb->creator_os);
[01ab41b]624}
625
[2226cc3]626/** Set operation system identifier, on which the filesystem was created.
[9fc72fb3]627 *
[38542dc]628 * @param sb Superblock
629 * @param os Operation system identifier
630 *
[9fc72fb3]631 */
[fe27eb4]632void ext4_superblock_set_creator_os(ext4_superblock_t *sb, uint32_t os)
633{
634 sb->creator_os = host2uint32_t_le(os);
635}
636
[2226cc3]637/** Get revision level of the filesystem.
[9fc72fb3]638 *
[38542dc]639 * @param sb Superblock
640 *
641 * @return Revision level
642 *
[9fc72fb3]643 */
[9c0c0e1]644uint32_t ext4_superblock_get_rev_level(ext4_superblock_t *sb)
645{
646 return uint32_t_le2host(sb->rev_level);
647}
648
[2226cc3]649/** Set revision level of the filesystem.
[9fc72fb3]650 *
[38542dc]651 * @param sb Superblock
652 * @param level Revision level
653 *
[9fc72fb3]654 */
[fe27eb4]655void ext4_superblock_set_rev_level(ext4_superblock_t *sb, uint32_t level)
656{
657 sb->rev_level = host2uint32_t_le(level);
658}
659
[2226cc3]660/** Get default user id for reserved blocks.
[9fc72fb3]661 *
[38542dc]662 * @param sb Superblock
663 *
664 * @return Default user id for reserved blocks.
665 *
[9fc72fb3]666 */
[fe27eb4]667uint16_t ext4_superblock_get_def_resuid(ext4_superblock_t *sb)
668{
669 return uint16_t_le2host(sb->def_resuid);
670}
671
[2226cc3]672/** Set default user id for reserved blocks.
[9fc72fb3]673 *
[38542dc]674 * @param sb Superblock
675 * @param uid Default user id for reserved blocks.
676 *
[9fc72fb3]677 */
[fe27eb4]678void ext4_superblock_set_def_resuid(ext4_superblock_t *sb, uint16_t uid)
679{
680 sb->def_resuid = host2uint16_t_le(uid);
681}
682
[2226cc3]683/** Get default group id for reserved blocks.
[9fc72fb3]684 *
[38542dc]685 * @param sb Superblock
686 *
687 * @return Default group id for reserved blocks.
688 *
[9fc72fb3]689 */
[fe27eb4]690uint16_t ext4_superblock_get_def_resgid(ext4_superblock_t *sb)
691{
692 return uint16_t_le2host(sb->def_resgid);
693}
694
[2226cc3]695/** Set default group id for reserved blocks.
[9fc72fb3]696 *
[38542dc]697 * @param sb Superblock
698 * @param gid Default group id for reserved blocks.
699 *
[9fc72fb3]700 */
[fe27eb4]701void ext4_superblock_set_def_resgid(ext4_superblock_t *sb, uint16_t gid)
702{
703 sb->def_resgid = host2uint16_t_le(gid);
704}
705
[2226cc3]706/** Get index of the first i-node, which can be used for allocation.
[9fc72fb3]707 *
[38542dc]708 * @param sb Superblock
709 *
710 * @return I-node index
711 *
[9fc72fb3]712 */
[fe27eb4]713uint32_t ext4_superblock_get_first_inode(ext4_superblock_t *sb)
714{
[aab85d90]715 if (ext4_superblock_get_rev_level(sb) == 0)
716 return EXT4_REV0_FIRST_INO;
717
[fe27eb4]718 return uint32_t_le2host(sb->first_inode);
719}
720
[2226cc3]721/** Set index of the first i-node, which can be used for allocation.
[9fc72fb3]722 *
[38542dc]723 * @param sb Superblock
724 * @param first_inode I-node index
725 *
[9fc72fb3]726 */
[38542dc]727void ext4_superblock_set_first_inode(ext4_superblock_t *sb,
728 uint32_t first_inode)
[fe27eb4]729{
730 sb->first_inode = host2uint32_t_le(first_inode);
731}
732
[2226cc3]733/** Get size of i-node structure.
734 *
735 * For the oldest revision return constant number.
[9fc72fb3]736 *
[38542dc]737 * @param sb Superblock
738 *
739 * @return Size of i-node structure
740 *
[9fc72fb3]741 */
[3711e7e]742uint16_t ext4_superblock_get_inode_size(ext4_superblock_t *sb)
743{
[38542dc]744 if (ext4_superblock_get_rev_level(sb) == 0)
[3711e7e]745 return EXT4_REV0_INODE_SIZE;
[a35b458]746
[3711e7e]747 return uint16_t_le2host(sb->inode_size);
748}
749
[2226cc3]750/** Set size of i-node structure.
[9fc72fb3]751 *
[38542dc]752 * @param sb Superblock
753 * @param size Size of i-node structure
754 *
[9fc72fb3]755 */
[fe27eb4]756void ext4_superblock_set_inode_size(ext4_superblock_t *sb, uint16_t size)
757{
758 sb->inode_size = host2uint16_t_le(size);
759}
760
[2226cc3]761/** Get index of block group, where superblock copy is located.
[9fc72fb3]762 *
[38542dc]763 * @param sb Superblock
764 *
765 * @return Block group index
766 *
[9fc72fb3]767 */
[2226cc3]768uint16_t ext4_superblock_get_block_group_index(ext4_superblock_t *sb)
[3711e7e]769{
[2226cc3]770 return uint16_t_le2host(sb->block_group_index);
[3711e7e]771}
772
[2226cc3]773/** Set index of block group, where superblock copy is located.
[9fc72fb3]774 *
[38542dc]775 * @param sb Superblock
776 * @param bgid Block group index
777 *
[9fc72fb3]778 */
[2226cc3]779void ext4_superblock_set_block_group_index(ext4_superblock_t *sb, uint16_t bgid)
[fe27eb4]780{
[2226cc3]781 sb->block_group_index = host2uint16_t_le(bgid);
[fe27eb4]782}
783
[2226cc3]784/** Get compatible features supported by the filesystem.
[9fc72fb3]785 *
[38542dc]786 * @param sb Superblock
787 *
788 * @return Compatible features bitmap
789 *
[9fc72fb3]790 */
[9c0c0e1]791uint32_t ext4_superblock_get_features_compatible(ext4_superblock_t *sb)
792{
793 return uint32_t_le2host(sb->features_compatible);
794}
795
[2226cc3]796/** Set compatible features supported by the filesystem.
[9fc72fb3]797 *
[38542dc]798 * @param sb Superblock
799 * @param features Compatible features bitmap
800 *
[9fc72fb3]801 */
[38542dc]802void ext4_superblock_set_features_compatible(ext4_superblock_t *sb,
803 uint32_t features)
[fe27eb4]804{
805 sb->features_compatible = host2uint32_t_le(features);
806}
807
[2226cc3]808/** Get incompatible features supported by the filesystem.
[9fc72fb3]809 *
[38542dc]810 * @param sb Superblock
811 *
812 * @return Incompatible features bitmap
813 *
[9fc72fb3]814 */
[9c0c0e1]815uint32_t ext4_superblock_get_features_incompatible(ext4_superblock_t *sb)
816{
817 return uint32_t_le2host(sb->features_incompatible);
818}
819
[2226cc3]820/** Set incompatible features supported by the filesystem.
[9fc72fb3]821 *
[38542dc]822 * @param sb Superblock
823 * @param features Incompatible features bitmap
824 *
[9fc72fb3]825 */
[38542dc]826void ext4_superblock_set_features_incompatible(ext4_superblock_t *sb,
827 uint32_t features)
[fe27eb4]828{
829 sb->features_incompatible = host2uint32_t_le(features);
830}
831
[2226cc3]832/** Get compatible features supported by the filesystem.
[9fc72fb3]833 *
[38542dc]834 * @param sb Superblock
835 *
836 * @return Read-only compatible features bitmap
837 *
[9fc72fb3]838 */
[9c0c0e1]839uint32_t ext4_superblock_get_features_read_only(ext4_superblock_t *sb)
840{
841 return uint32_t_le2host(sb->features_read_only);
842}
843
[2226cc3]844/** Set compatible features supported by the filesystem.
[9fc72fb3]845 *
[38542dc]846 * @param sb Superblock
847 * @param feature Read-only compatible features bitmap
848 *
[9fc72fb3]849 */
[38542dc]850void ext4_superblock_set_features_read_only(ext4_superblock_t *sb,
851 uint32_t features)
[fe27eb4]852{
853 sb->features_read_only = host2uint32_t_le(features);
854}
[01ab41b]855
[2226cc3]856/** Get UUID of the filesystem.
[9fc72fb3]857 *
[38542dc]858 * @param sb superblock
859 *
860 * @return Pointer to UUID array
861 *
[9fc72fb3]862 */
[aab85d90]863void ext4_superblock_get_uuid(ext4_superblock_t *sb, uuid_t *uuid)
[291af81]864{
[aab85d90]865 uuid_decode(sb->uuid, uuid);
[291af81]866}
867
[2226cc3]868/** Set UUID of the filesystem.
[9fc72fb3]869 *
[38542dc]870 * @param sb Superblock
[aab85d90]871 * @param uuid Pointer to UUID
[38542dc]872 *
[9fc72fb3]873 */
[aab85d90]874void ext4_superblock_set_uuid(ext4_superblock_t *sb, uuid_t *uuid)
[291af81]875{
[aab85d90]876 uuid_encode(uuid, sb->uuid);
[291af81]877}
878
[2226cc3]879/** Get name of the filesystem volume.
880 *
[38542dc]881 * @param sb Superblock
882 *
883 * @return Name of the volume
884 *
[2226cc3]885 */
[b209135]886errno_t ext4_superblock_get_volume_name(ext4_superblock_t *sb, char *buf,
887 size_t bufsz)
[291af81]888{
[b209135]889 size_t i;
890 size_t wi;
891 wchar_t ch;
892 errno_t rc;
893
894 i = 0;
895 wi = 0;
896 while (sb->volume_name[i] != '\0' && i < sizeof(sb->volume_name)) {
897 /* ISO 8859-1 codes map to identical Unicode code points */
898 ch = (wchar_t)(uint8_t)sb->volume_name[i];
899 rc = chr_encode(ch, buf, &wi, bufsz - 1);
900 if (rc != EOK)
901 return rc;
902
903 i++;
904 }
905
906 buf[wi] = '\0';
907 return EOK;
[291af81]908}
909
[2226cc3]910/** Set name of the filesystem volume.
[9fc72fb3]911 *
[38542dc]912 * @param sb Superblock
913 * @param name New name of the volume
[9fc72fb3]914 */
[291af81]915void ext4_superblock_set_volume_name(ext4_superblock_t *sb, const char *name)
916{
917 memcpy(sb->volume_name, name, sizeof(sb->volume_name));
918}
919
[2226cc3]920/** Get name of the directory, where this filesystem was mounted at last.
[9fc72fb3]921 *
[38542dc]922 * @param sb Superblock
923 *
924 * @return Directory name
925 *
[9fc72fb3]926 */
[38542dc]927const char *ext4_superblock_get_last_mounted(ext4_superblock_t *sb)
[291af81]928{
929 return sb->last_mounted;
930}
931
[2226cc3]932/** Set name of the directory, where this filesystem was mounted at last.
[9fc72fb3]933 *
[38542dc]934 * @param sb Superblock
935 * @param last Directory name
936 *
[9fc72fb3]937 */
[291af81]938void ext4_superblock_set_last_mounted(ext4_superblock_t *sb, const char *last)
939{
940 memcpy(sb->last_mounted, last, sizeof(sb->last_mounted));
941}
942
[2226cc3]943/** Get last orphaned i-node index.
944 *
945 * Orphans are stored in linked list.
[9fc72fb3]946 *
[38542dc]947 * @param sb Superblock
948 *
949 * @return Last orphaned i-node index
950 *
[9fc72fb3]951 */
[ebcaff4]952uint32_t ext4_superblock_get_last_orphan(ext4_superblock_t *sb)
953{
954 return uint32_t_le2host(sb->last_orphan);
955}
956
[2226cc3]957/** Set last orphaned i-node index.
958 *
959 * Orphans are stored in linked list.
[9fc72fb3]960 *
[38542dc]961 * @param sb Superblock
962 * @param last_orphan Last orphaned i-node index
963 *
[9fc72fb3]964 */
[38542dc]965void ext4_superblock_set_last_orphan(ext4_superblock_t *sb,
966 uint32_t last_orphan)
[ebcaff4]967{
968 sb->last_orphan = host2uint32_t_le(last_orphan);
969}
970
[2226cc3]971/** Get hash seed for directory index hash function.
[9fc72fb3]972 *
[38542dc]973 * @param sb Superblock
974 *
975 * @return Hash seed pointer
976 *
[9fc72fb3]977 */
[38542dc]978const uint32_t *ext4_superblock_get_hash_seed(ext4_superblock_t *sb)
[7bc4508]979{
980 return sb->hash_seed;
981}
982
[2226cc3]983/** Set hash seed for directory index hash function.
[9fc72fb3]984 *
[38542dc]985 * @param sb Superblock
986 * @param seed Hash seed pointer
987 *
[2226cc3]988 */
989void ext4_superblock_set_hash_seed(ext4_superblock_t *sb, const uint32_t *seed)
990{
991 memcpy(sb->hash_seed, seed, sizeof(sb->hash_seed));
992}
993
994/** Get default version of the hash algorithm version for directory index.
995 *
[38542dc]996 * @param sb Superblock
997 *
998 * @return Default hash version
999 *
[9fc72fb3]1000 */
[7eb033ce]1001uint8_t ext4_superblock_get_default_hash_version(ext4_superblock_t *sb)
1002{
1003 return sb->default_hash_version;
1004}
1005
[2226cc3]1006/** Set default version of the hash algorithm version for directory index.
[9fc72fb3]1007 *
[38542dc]1008 * @param sb Superblock
1009 * @param version Default hash version
1010 *
[9fc72fb3]1011 */
[38542dc]1012void ext4_superblock_set_default_hash_version(ext4_superblock_t *sb,
1013 uint8_t version)
[7eb033ce]1014{
1015 sb->default_hash_version = version;
1016}
1017
[2226cc3]1018/** Get size of block group descriptor structure.
[9fc72fb3]1019 *
[2226cc3]1020 * Output value is checked for minimal size.
1021 *
[38542dc]1022 * @param sb Superblock
1023 *
1024 * @return Size of block group descriptor
1025 *
[9fc72fb3]1026 */
[c25e39b]1027uint16_t ext4_superblock_get_desc_size(ext4_superblock_t *sb)
1028{
1029 uint16_t size = uint16_t_le2host(sb->desc_size);
[a35b458]1030
[38542dc]1031 if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
[fb04cd90]1032 size = EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE;
[a35b458]1033
[c25e39b]1034 return size;
1035}
1036
[2226cc3]1037/** Set size of block group descriptor structure.
1038 *
1039 * Input value is checked for minimal size.
[9fc72fb3]1040 *
[38542dc]1041 * @param sb Superblock
1042 * @param size Size of block group descriptor
1043 *
[9fc72fb3]1044 */
[fe27eb4]1045void ext4_superblock_set_desc_size(ext4_superblock_t *sb, uint16_t size)
1046{
[38542dc]1047 if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
1048 sb->desc_size =
1049 host2uint16_t_le(EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE);
[a35b458]1050
[fe27eb4]1051 sb->desc_size = host2uint16_t_le(size);
1052}
1053
[2226cc3]1054/** Get superblock flags.
[9fc72fb3]1055 *
[38542dc]1056 * @param sb Superblock
1057 *
1058 * @return Flags from the superblock
1059 *
[9fc72fb3]1060 */
[7bc4508]1061uint32_t ext4_superblock_get_flags(ext4_superblock_t *sb)
1062{
1063 return uint32_t_le2host(sb->flags);
1064}
1065
[2226cc3]1066/** Set superblock flags.
[9fc72fb3]1067 *
[38542dc]1068 * @param sb Superblock
1069 * @param flags Flags for the superblock
1070 *
[9fc72fb3]1071 */
[fe27eb4]1072void ext4_superblock_set_flags(ext4_superblock_t *sb, uint32_t flags)
1073{
1074 sb->flags = host2uint32_t_le(flags);
1075}
1076
[3712434]1077/*
[c25e39b]1078 * More complex superblock operations
[01ab41b]1079 */
[3712434]1080
[2226cc3]1081/** Check if superblock has specified flag.
[9fc72fb3]1082 *
[38542dc]1083 * @param sb Superblock
1084 * @param flag Flag to be checked
1085 *
1086 * @return True, if superblock has the flag
1087 *
[9fc72fb3]1088 */
[7bc4508]1089bool ext4_superblock_has_flag(ext4_superblock_t *sb, uint32_t flag)
1090{
[38542dc]1091 if (ext4_superblock_get_flags(sb) & flag)
[7bc4508]1092 return true;
[a35b458]1093
[7bc4508]1094 return false;
1095}
1096
[2226cc3]1097/** Check if filesystem supports compatible feature.
[9fc72fb3]1098 *
[38542dc]1099 * @param sb Superblock
1100 * @param feature Feature to be checked
1101 *
1102 * @return True, if filesystem supports the feature
1103 *
[9fc72fb3]1104 */
[38542dc]1105bool ext4_superblock_has_feature_compatible(ext4_superblock_t *sb,
1106 uint32_t feature)
[c25e39b]1107{
[38542dc]1108 if (ext4_superblock_get_features_compatible(sb) & feature)
[c25e39b]1109 return true;
[a35b458]1110
[c25e39b]1111 return false;
1112}
1113
[2226cc3]1114/** Check if filesystem supports incompatible feature.
[9fc72fb3]1115 *
[38542dc]1116 * @param sb Superblock
1117 * @param feature Feature to be checked
1118 *
1119 * @return True, if filesystem supports the feature
1120 *
[9fc72fb3]1121 */
[38542dc]1122bool ext4_superblock_has_feature_incompatible(ext4_superblock_t *sb,
1123 uint32_t feature)
[c25e39b]1124{
[38542dc]1125 if (ext4_superblock_get_features_incompatible(sb) & feature)
[c25e39b]1126 return true;
[a35b458]1127
[c25e39b]1128 return false;
1129}
1130
[2226cc3]1131/** Check if filesystem supports read-only compatible feature.
[9fc72fb3]1132 *
[38542dc]1133 * @param sb Superblock
1134 * @param feature Feature to be checked
1135 *
1136 * @return True, if filesystem supports the feature
1137 *
[9fc72fb3]1138 */
[38542dc]1139bool ext4_superblock_has_feature_read_only(ext4_superblock_t *sb,
1140 uint32_t feature)
[c25e39b]1141{
[38542dc]1142 if (ext4_superblock_get_features_read_only(sb) & feature)
[c25e39b]1143 return true;
[a35b458]1144
[c25e39b]1145 return false;
1146}
1147
[2226cc3]1148/** Read superblock directly from block device.
[9fc72fb3]1149 *
[38542dc]1150 * @param service_id Block device identifier
1151 * @param sb Output pointer to memory structure
1152 *
1153 * @return Eerror code.
1154 *
[9fc72fb3]1155 */
[b7fd2a0]1156errno_t ext4_superblock_read_direct(service_id_t service_id, ext4_superblock_t **sb)
[01ab41b]1157{
[06d85e5]1158 /* Allocated memory for superblock structure */
[d9bbe45]1159 void *data = malloc(EXT4_SUPERBLOCK_SIZE);
[38542dc]1160 if (data == NULL)
[01ab41b]1161 return ENOMEM;
[a35b458]1162
[06d85e5]1163 /* Read data from block device */
[b7fd2a0]1164 errno_t rc = block_read_bytes_direct(service_id, EXT4_SUPERBLOCK_OFFSET,
[01ab41b]1165 EXT4_SUPERBLOCK_SIZE, data);
[a35b458]1166
[01ab41b]1167 if (rc != EOK) {
1168 free(data);
1169 return rc;
1170 }
[a35b458]1171
[06d85e5]1172 /* Set output value */
[2226cc3]1173 (*sb) = data;
[a35b458]1174
[01ab41b]1175 return EOK;
1176}
1177
[2226cc3]1178/** Write superblock structure directly to block device.
[9fc72fb3]1179 *
[38542dc]1180 * @param service_id Block device identifier
1181 * @param sb Superblock to be written
1182 *
1183 * @return Error code
1184 *
[9fc72fb3]1185 */
[b7fd2a0]1186errno_t ext4_superblock_write_direct(service_id_t service_id, ext4_superblock_t *sb)
[ae3d4f8]1187{
[06d85e5]1188 /* Load physical block size from block device */
[38542dc]1189 size_t phys_block_size;
[b7fd2a0]1190 errno_t rc = block_get_bsize(service_id, &phys_block_size);
[38542dc]1191 if (rc != EOK)
[ae3d4f8]1192 return rc;
[a35b458]1193
[06d85e5]1194 /* Compute address of the first block */
[d9bbe45]1195 uint64_t first_block = EXT4_SUPERBLOCK_OFFSET / phys_block_size;
[a35b458]1196
[06d85e5]1197 /* Compute number of block to write */
[80bd676]1198 size_t block_count = EXT4_SUPERBLOCK_SIZE / phys_block_size;
[a35b458]1199
[06d85e5]1200 /* Check alignment */
[38542dc]1201 if (EXT4_SUPERBLOCK_SIZE % phys_block_size)
[ae3d4f8]1202 block_count++;
[a35b458]1203
[06d85e5]1204 /* Write data */
[ae3d4f8]1205 return block_write_direct(service_id, first_block, block_count, sb);
1206}
1207
[eb94d84]1208/** Release the memory allocated for the superblock structure
1209 *
1210 * @param sb Superblock to be freed
1211 *
1212 */
1213void ext4_superblock_release(ext4_superblock_t *sb)
1214{
1215 free(sb);
1216}
1217
[5b26747]1218/** Check sanity of the superblock.
[9fc72fb3]1219 *
[5b26747]1220 * This check is performed at mount time.
1221 * Checks are described by one-line comments in the code.
1222 *
[38542dc]1223 * @param sb Superblock to check
1224 *
1225 * @return Error code
1226 *
[9fc72fb3]1227 */
[b7fd2a0]1228errno_t ext4_superblock_check_sanity(ext4_superblock_t *sb)
[01ab41b]1229{
[38542dc]1230 if (ext4_superblock_get_magic(sb) != EXT4_SUPERBLOCK_MAGIC)
[9c0c0e1]1231 return ENOTSUP;
[a35b458]1232
[38542dc]1233 if (ext4_superblock_get_inodes_count(sb) == 0)
[fb04cd90]1234 return ENOTSUP;
[a35b458]1235
[38542dc]1236 if (ext4_superblock_get_blocks_count(sb) == 0)
[fb04cd90]1237 return ENOTSUP;
[a35b458]1238
[38542dc]1239 if (ext4_superblock_get_blocks_per_group(sb) == 0)
[fb04cd90]1240 return ENOTSUP;
[a35b458]1241
[38542dc]1242 if (ext4_superblock_get_inodes_per_group(sb) == 0)
[fb04cd90]1243 return ENOTSUP;
[a35b458]1244
[38542dc]1245 if (ext4_superblock_get_inode_size(sb) < 128)
[fb04cd90]1246 return ENOTSUP;
[a35b458]1247
[38542dc]1248 if (ext4_superblock_get_first_inode(sb) < 11)
[fb04cd90]1249 return ENOTSUP;
[a35b458]1250
[38542dc]1251 if (ext4_superblock_get_desc_size(sb) <
1252 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
[fb04cd90]1253 return ENOTSUP;
[a35b458]1254
[38542dc]1255 if (ext4_superblock_get_desc_size(sb) >
1256 EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE)
[fb04cd90]1257 return ENOTSUP;
[a35b458]1258
[01ab41b]1259 return EOK;
1260}
[eb91db7]1261
[2226cc3]1262/** Compute number of block groups in the filesystem.
[9fc72fb3]1263 *
[38542dc]1264 * @param sb Superblock
1265 *
1266 * @return Number of block groups
1267 *
[9fc72fb3]1268 */
[b12ca16]1269uint32_t ext4_superblock_get_block_group_count(ext4_superblock_t *sb)
1270{
[5cef315]1271 uint64_t blocks_count = ext4_superblock_get_blocks_count(sb) - 1;
[b12ca16]1272 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
[a35b458]1273
[b12ca16]1274 uint32_t block_groups_count = blocks_count / blocks_per_group;
[a35b458]1275
[38542dc]1276 if (blocks_count % blocks_per_group)
[b12ca16]1277 block_groups_count++;
[a35b458]1278
[b12ca16]1279 return block_groups_count;
1280}
1281
[2226cc3]1282/** Compute number of blocks in specified block group.
[9fc72fb3]1283 *
[38542dc]1284 * @param sb Superblock
1285 * @param bgid Block group index
1286 *
1287 * @return Number of blocks
1288 *
[9fc72fb3]1289 */
[b12ca16]1290uint32_t ext4_superblock_get_blocks_in_group(ext4_superblock_t *sb, uint32_t bgid)
1291{
[38542dc]1292 uint32_t block_group_count =
1293 ext4_superblock_get_block_group_count(sb);
1294 uint32_t blocks_per_group =
1295 ext4_superblock_get_blocks_per_group(sb);
1296 uint64_t total_blocks =
[5cef315]1297 ext4_superblock_get_blocks_count(sb) - 1;
[a35b458]1298
[38542dc]1299 if (bgid < block_group_count - 1)
[b12ca16]1300 return blocks_per_group;
[38542dc]1301 else
[b12ca16]1302 return (total_blocks - ((block_group_count - 1) * blocks_per_group));
1303}
1304
[2226cc3]1305/** Compute number of i-nodes in specified block group.
[9fc72fb3]1306 *
[38542dc]1307 * @param sb Superblock
1308 * @param bgid Block group index
1309 *
1310 * @return Number of i-nodes
1311 *
[9fc72fb3]1312 */
[b12ca16]1313uint32_t ext4_superblock_get_inodes_in_group(ext4_superblock_t *sb, uint32_t bgid)
1314{
[38542dc]1315 uint32_t block_group_count =
1316 ext4_superblock_get_block_group_count(sb);
1317 uint32_t inodes_per_group =
1318 ext4_superblock_get_inodes_per_group(sb);
1319 uint32_t total_inodes =
1320 ext4_superblock_get_inodes_count(sb);
[a35b458]1321
[38542dc]1322 if (bgid < block_group_count - 1)
[b12ca16]1323 return inodes_per_group;
[38542dc]1324 else
[b12ca16]1325 return (total_inodes - ((block_group_count - 1) * inodes_per_group));
1326}
1327
[6dd7f65]1328/** Get the backup groups used with SPARSE_SUPER2
1329 *
1330 * @param sb Pointer to the superblock
1331 * @param g1 Output pointer to the first backup group
1332 * @param g2 Output pointer to the second backup group
1333 */
1334void ext4_superblock_get_backup_groups_sparse2(ext4_superblock_t *sb,
1335 uint32_t *g1, uint32_t *g2)
1336{
1337 *g1 = uint32_t_le2host(sb->backup_bgs[0]);
1338 *g2 = uint32_t_le2host(sb->backup_bgs[1]);
1339}
1340
1341/** Set the backup groups (SPARSE SUPER2)
1342 *
1343 * @param sb Pointer to the superblock
1344 * @param g1 Index of the first group
1345 * @param g2 Index of the second group
1346 */
1347void ext4_superblock_set_backup_groups_sparse2(ext4_superblock_t *sb,
1348 uint32_t g1, uint32_t g2)
1349{
1350 sb->backup_bgs[0] = host2uint32_t_le(g1);
1351 sb->backup_bgs[1] = host2uint32_t_le(g2);
1352}
1353
1354/** Get the number of blocks (per group) reserved to GDT expansion
1355 *
1356 * @param sb Pointer to the superblock
1357 *
1358 * @return Number of blocks
1359 */
1360uint32_t ext4_superblock_get_reserved_gdt_blocks(ext4_superblock_t *sb)
1361{
1362 return uint32_t_le2host(sb->reserved_gdt_blocks);
1363}
1364
1365/** Set the number of blocks (per group) reserved to GDT expansion
1366 *
1367 * @param sb Pointer to the superblock
1368 * @param n Number of reserved blocks
1369 */
1370void ext4_superblock_set_reserved_gdt_blocks(ext4_superblock_t *sb,
1371 uint32_t n)
1372{
1373 sb->reserved_gdt_blocks = host2uint32_t_le(n);
1374}
1375
[aab85d90]1376/* Check if n is a power of p */
1377static bool is_power_of(uint32_t n, unsigned p)
1378{
1379 if (p == 1 && n != p)
1380 return false;
1381
1382 while (n != p) {
1383 if (n < p)
1384 return false;
1385 else if ((n % p) != 0)
1386 return false;
1387
1388 n /= p;
1389 }
1390
1391 return true;
1392}
1393
1394/** Get the number of blocks used by superblock + gdt + reserved gdt backups
1395 *
1396 * @param sb Superblock
1397 * @param idx Block group index
1398 *
1399 * @return Number of blocks
1400 */
1401uint32_t ext4_superblock_get_group_backup_blocks(ext4_superblock_t *sb,
1402 uint32_t idx)
1403{
1404 uint32_t r = 0;
1405 bool has_backups = false;
1406
1407 /* First step: determine if the block group contains the backups */
1408
1409 if (idx <= 1)
1410 has_backups = true;
1411 else {
1412 if (ext4_superblock_has_feature_compatible(sb,
1413 EXT4_FEATURE_COMPAT_SPARSE_SUPER2)) {
1414 uint32_t g1, g2;
1415
1416 ext4_superblock_get_backup_groups_sparse2(sb,
1417 &g1, &g2);
1418
1419 if (idx == g1 || idx == g2)
1420 has_backups = true;
1421 } else if (!ext4_superblock_has_feature_read_only(sb,
1422 EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
1423 /*
1424 * Very old fs were all block groups have
1425 * superblock and block descriptors backups.
1426 */
1427 has_backups = true;
1428 } else {
1429 if ((idx & 1) && (is_power_of(idx, 3) ||
1430 is_power_of(idx, 5) || is_power_of(idx, 7)))
1431 has_backups = true;
1432 }
1433 }
1434
1435 if (has_backups) {
1436 uint32_t bg_count;
1437 uint32_t bg_desc_sz;
1438 uint32_t gdt_table; /* Size of the GDT in blocks */
1439 uint32_t block_size = ext4_superblock_get_block_size(sb);
1440
1441 /*
1442 * Now we know that this block group has backups,
1443 * we have to compute how many blocks are reserved
1444 * for them
1445 */
1446
1447 if (idx == 0 && block_size == 1024) {
1448 /*
1449 * Special case for first group were the boot block
1450 * resides
1451 */
1452 r++;
1453 }
1454
1455 /* This accounts for the superblock */
1456 r++;
1457
1458 /* Add the number of blocks used for the GDT */
1459 bg_count = ext4_superblock_get_block_group_count(sb);
1460 bg_desc_sz = ext4_superblock_get_desc_size(sb);
1461 gdt_table = ROUND_UP(bg_count * bg_desc_sz, block_size) /
1462 block_size;
1463
1464 r += gdt_table;
1465
1466 /* And now the number of reserved GDT blocks */
1467 r += ext4_superblock_get_reserved_gdt_blocks(sb);
1468 }
1469
1470 return r;
1471}
1472
1473/** Create superblock for new file system.
1474 *
1475 * @param dev_bsize Device block size
1476 * @param dev_bcnt Device number of blocks
[2175178]1477 * @param ver Filesystem version
[aab85d90]1478 * @param rsb Place to store pointer to newly allocated superblock
1479 * @return EOK on success or error code
1480 */
1481errno_t ext4_superblock_create(size_t dev_bsize, uint64_t dev_bcnt,
[2175178]1482 ext4_cfg_ver_t ver, ext4_superblock_t **rsb)
[aab85d90]1483{
1484 ext4_superblock_t *sb;
1485 uuid_t uuid;
1486 uint32_t cur_ts;
1487 uint64_t first_block;
1488 uint64_t fs_blocks;
1489 uint32_t blocks_count;
1490 uint32_t free_blocks;
1491 uint32_t inodes_count;
1492 uint64_t blocks_group;
1493 uint64_t inodes_group;
1494 uint32_t inodes_block;
1495 uint32_t inode_table_blocks;
1496 uint32_t res_blocks;
1497 uint32_t ngroups;
1498 uint32_t idx;
1499 size_t fs_bsize;
1500 errno_t rc;
1501 struct timespec ts;
1502
1503 sb = calloc(1, sizeof(ext4_superblock_t));
1504 if (sb == NULL)
1505 return ENOMEM;
1506
1507 rc = uuid_generate(&uuid);
1508 if (rc != EOK)
1509 goto error;
1510
1511 /* Current UNIX time */
1512 getrealtime(&ts); // XXX ISO C does not say what the epoch is
1513 cur_ts = ts.tv_sec;
1514
1515 fs_bsize = 1024;
1516 first_block = 1; /* 1 for 1k block size, 0 otherwise */
1517
1518 if (fs_bsize % dev_bsize == 0) {
1519 /* Small device blocks */
1520 fs_blocks = dev_bcnt / (fs_bsize / dev_bsize);
1521 } else {
1522 /* Large device blocks */
1523 fs_blocks = dev_bcnt * (dev_bsize / fs_bsize);
1524 }
1525
1526 /* FS blocks per group */
1527 blocks_group = 8 * fs_bsize;
1528
1529 /* Inodes per group */
1530 inodes_block = fs_bsize / EXT4_REV0_INODE_SIZE;
1531 inodes_group = min((fs_blocks - first_block) / 8,
1532 blocks_group / 4);
1533 if (inodes_group < 16)
1534 inodes_group = 16;
1535
1536 /* Align up to multiple of inodes_block */
1537 if (inodes_group % inodes_block != 0)
1538 inodes_group += inodes_block - inodes_group % inodes_block;
1539 inode_table_blocks = inodes_group / inodes_block;
1540
1541 /* Number of groups */
1542 ngroups = ((fs_blocks - first_block) + blocks_group - 1) / blocks_group;
1543
1544 /* Count of all blocks in groups */
1545 blocks_count = fs_blocks - first_block;
1546
1547 /* Count of all inodes */
1548 inodes_count = ngroups * inodes_group;
1549
1550 /* Count of blocks reserved for superuser */
1551 res_blocks = (blocks_count + 19) / 20;
1552
1553 free_blocks = blocks_count;
1554
1555 ext4_superblock_set_magic(sb, EXT4_SUPERBLOCK_MAGIC);
1556 ext4_superblock_set_inodes_count(sb, inodes_count);
[5cef315]1557 /* This seems to include the boot block, despite the ext2fs docs */
1558 ext4_superblock_set_blocks_count(sb, fs_blocks);
[aab85d90]1559 ext4_superblock_set_reserved_blocks_count(sb, res_blocks);
1560 ext4_superblock_set_free_blocks_count(sb, free_blocks);
1561 ext4_superblock_set_free_inodes_count(sb, inodes_count);
1562 ext4_superblock_set_first_data_block(sb, first_block);
1563 /* Block size will be 1024 bytes */
1564 ext4_superblock_set_log_block_size(sb, 0);
1565 /* Fragment size should be equal to block size */
1566 ext4_superblock_set_log_frag_size(sb, 0);
1567 ext4_superblock_set_blocks_per_group(sb, blocks_group);
1568 /* Should be the same as blocks per group. */
1569 ext4_superblock_set_frags_per_group(sb, blocks_group);
1570 ext4_superblock_set_inodes_per_group(sb, inodes_group);
1571 ext4_superblock_set_mount_time(sb, 0);
1572 ext4_superblock_set_write_time(sb, cur_ts);
1573 ext4_superblock_set_mount_count(sb, 0);
1574 ext4_superblock_set_max_mount_count(sb, (uint16_t)-1);
1575 ext4_superblock_set_state(sb, EXT4_SUPERBLOCK_STATE_VALID_FS);
1576 ext4_superblock_set_errors(sb, EXT4_SUPERBLOCK_ERRORS_CONTINUE);
1577 ext4_superblock_set_minor_rev_level(sb, 0); // XXX
1578 ext4_superblock_set_last_check_time(sb, cur_ts);
1579 ext4_superblock_set_check_interval(sb, 0);
1580 ext4_superblock_set_creator_os(sb, EXT4_SUPERBLOCK_OS_LINUX);
[2175178]1581 if (ver >= extver_ext2)
1582 ext4_superblock_set_rev_level(sb, EXT4_DYNAMIC_REV);
1583 else
1584 ext4_superblock_set_rev_level(sb, EXT4_GOOD_OLD_REV);
[aab85d90]1585 ext4_superblock_set_def_resuid(sb, 0);
1586 ext4_superblock_set_def_resgid(sb, 0);
1587
[2175178]1588 if (ver >= extver_ext2) {
1589 /* Dynamic rev */
1590 ext4_superblock_set_first_inode(sb, EXT4_REV0_FIRST_INO);
1591 ext4_superblock_set_inode_size(sb, EXT4_REV0_INODE_SIZE);
1592 ext4_superblock_set_block_group_index(sb, 0); // XXX
1593 ext4_superblock_set_features_compatible(sb, 0);
1594 ext4_superblock_set_features_incompatible(sb, 0);
1595 ext4_superblock_set_features_read_only(sb, 0);
1596
1597 ext4_superblock_set_uuid(sb, &uuid);
1598 /* 16-byte Latin-1 string padded with null characters */
1599 ext4_superblock_set_volume_name(sb, "HelenOS-Ext4\0\0\0\0");
1600 /* 64-byte Latin-1 string padded with null characters */
1601 ext4_superblock_set_last_mounted(sb,
1602 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1603 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
1604 sb->algorithm_usage_bitmap = 0;
1605 }
1606#if 0
[aab85d90]1607 /* Journalling */
1608 ext4_superblock_set_desc_size(sb, EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE);
1609#endif
1610
1611 /* Compute free blocks */
1612 free_blocks = blocks_count;
[5cef315]1613 ++free_blocks; // XXX Why?
[aab85d90]1614 for (idx = 0; idx < ngroups; idx++) {
1615 free_blocks -= ext4_superblock_get_group_backup_blocks(sb, idx);
1616 /* One for block bitmap, one for inode bitamp */
1617 free_blocks -= 2;
1618 free_blocks -= inode_table_blocks;
1619 }
1620
1621 ext4_superblock_set_free_blocks_count(sb, free_blocks);
1622
1623 *rsb = sb;
1624 return EOK;
1625error:
1626 free(sb);
1627 return rc;
1628}
1629
[eb91db7]1630/**
1631 * @}
[38542dc]1632 */
Note: See TracBrowser for help on using the repository browser.