Home | History | Annotate | Download | only in ext2fs
      1 /*
      2  * blknum.c --- Functions to handle blk64_t and high/low 64-bit block
      3  * number.
      4  *
      5  * Copyright IBM Corporation, 2007
      6  * Author Jose R. Santos <jrs (at) us.ibm.com>
      7  *
      8  * %Begin-Header%
      9  * This file may be redistributed under the terms of the GNU Public
     10  * License.
     11  * %End-Header%
     12  */
     13 
     14 #include "config.h"
     15 #include "ext2fs.h"
     16 
     17 /*
     18  * Return the group # of a block
     19  */
     20 dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t blk)
     21 {
     22 	return (blk - fs->super->s_first_data_block) /
     23 		fs->super->s_blocks_per_group;
     24 }
     25 
     26 /*
     27  * Return the first block (inclusive) in a group
     28  */
     29 blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group)
     30 {
     31 	return fs->super->s_first_data_block +
     32 		EXT2_GROUPS_TO_BLOCKS(fs->super, group);
     33 }
     34 
     35 /*
     36  * Return the last block (inclusive) in a group
     37  */
     38 blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group)
     39 {
     40 	return (group == fs->group_desc_count - 1 ?
     41 		ext2fs_blocks_count(fs->super) - 1 :
     42 		ext2fs_group_first_block2(fs, group) +
     43 			(fs->super->s_blocks_per_group - 1));
     44 }
     45 
     46 /*
     47  * Return the number of blocks in a group
     48  */
     49 int ext2fs_group_blocks_count(ext2_filsys fs, dgrp_t group)
     50 {
     51 	int num_blocks;
     52 
     53 	if (group == fs->group_desc_count - 1) {
     54 		num_blocks = (ext2fs_blocks_count(fs->super) -
     55 				fs->super->s_first_data_block) %
     56 			      fs->super->s_blocks_per_group;
     57 		if (!num_blocks)
     58 			num_blocks = fs->super->s_blocks_per_group;
     59 	} else
     60 		num_blocks = fs->super->s_blocks_per_group;
     61 
     62 	return num_blocks;
     63 }
     64 
     65 /*
     66  * Return the inode data block count
     67  */
     68 blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs,
     69 					struct ext2_inode *inode)
     70 {
     71 	return (inode->i_blocks |
     72 		(ext2fs_has_feature_huge_file(fs->super) ?
     73 		 (__u64) inode->osd2.linux2.l_i_blocks_hi << 32 : 0)) -
     74 		(inode->i_file_acl ? fs->blocksize >> 9 : 0);
     75 }
     76 
     77 /*
     78  * Return the inode i_blocks count
     79  */
     80 blk64_t ext2fs_inode_i_blocks(ext2_filsys fs,
     81 					struct ext2_inode *inode)
     82 {
     83 	return (inode->i_blocks |
     84 		(ext2fs_has_feature_huge_file(fs->super) ?
     85 		 (__u64)inode->osd2.linux2.l_i_blocks_hi << 32 : 0));
     86 }
     87 
     88 /*
     89  * Return the fs block count
     90  */
     91 blk64_t ext2fs_blocks_count(struct ext2_super_block *super)
     92 {
     93 	return super->s_blocks_count |
     94 		(ext2fs_has_feature_64bit(super) ?
     95 		(__u64) super->s_blocks_count_hi << 32 : 0);
     96 }
     97 
     98 /*
     99  * Set the fs block count
    100  */
    101 void ext2fs_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
    102 {
    103 	super->s_blocks_count = blk;
    104 	if (ext2fs_has_feature_64bit(super))
    105 		super->s_blocks_count_hi = (__u64) blk >> 32;
    106 }
    107 
    108 /*
    109  * Add to the current fs block count
    110  */
    111 void ext2fs_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
    112 {
    113 	blk64_t tmp;
    114 	tmp = ext2fs_blocks_count(super) + blk;
    115 	ext2fs_blocks_count_set(super, tmp);
    116 }
    117 
    118 /*
    119  * Return the fs reserved block count
    120  */
    121 blk64_t ext2fs_r_blocks_count(struct ext2_super_block *super)
    122 {
    123 	return super->s_r_blocks_count |
    124 		(ext2fs_has_feature_64bit(super) ?
    125 		(__u64) super->s_r_blocks_count_hi << 32 : 0);
    126 }
    127 
    128 /*
    129  * Set the fs reserved block count
    130  */
    131 void ext2fs_r_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
    132 {
    133 	super->s_r_blocks_count = blk;
    134 	if (ext2fs_has_feature_64bit(super))
    135 		super->s_r_blocks_count_hi = (__u64) blk >> 32;
    136 }
    137 
    138 /*
    139  * Add to the current reserved fs block count
    140  */
    141 void ext2fs_r_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
    142 {
    143 	blk64_t tmp;
    144 	tmp = ext2fs_r_blocks_count(super) + blk;
    145 	ext2fs_r_blocks_count_set(super, tmp);
    146 }
    147 
    148 /*
    149  * Return the fs free block count
    150  */
    151 blk64_t ext2fs_free_blocks_count(struct ext2_super_block *super)
    152 {
    153 	return super->s_free_blocks_count |
    154 		(ext2fs_has_feature_64bit(super) ?
    155 		(__u64) super->s_free_blocks_hi << 32 : 0);
    156 }
    157 
    158 /*
    159  * Set the fs free block count
    160  */
    161 void ext2fs_free_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
    162 {
    163 	super->s_free_blocks_count = blk;
    164 	if (ext2fs_has_feature_64bit(super))
    165 		super->s_free_blocks_hi = (__u64) blk >> 32;
    166 }
    167 
    168 /*
    169  * Add to the current free fs block count
    170  */
    171 void ext2fs_free_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
    172 {
    173 	blk64_t tmp;
    174 	tmp = ext2fs_free_blocks_count(super) + blk;
    175 	ext2fs_free_blocks_count_set(super, tmp);
    176 }
    177 
    178 /*
    179  * Get a pointer to a block group descriptor.  We need the explicit
    180  * pointer to the group desc for code that swaps block group
    181  * descriptors before writing them out, as it wants to make a copy and
    182  * do the swap there.
    183  */
    184 struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
    185 					  struct opaque_ext2_group_desc *gdp,
    186 					  dgrp_t group)
    187 {
    188 	int desc_size = EXT2_DESC_SIZE(fs->super) & ~7;
    189 
    190 	return (struct ext2_group_desc *)((char *)gdp + group * desc_size);
    191 }
    192 
    193 /* Do the same but as an ext4 group desc for internal use here */
    194 static struct ext4_group_desc *ext4fs_group_desc(ext2_filsys fs,
    195 					  struct opaque_ext2_group_desc *gdp,
    196 					  dgrp_t group)
    197 {
    198 	return (struct ext4_group_desc *)ext2fs_group_desc(fs, gdp, group);
    199 }
    200 
    201 /*
    202  * Return the block bitmap checksum of a group
    203  */
    204 __u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group)
    205 {
    206 	struct ext4_group_desc *gdp;
    207 	__u32 csum;
    208 
    209 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    210 	csum = gdp->bg_block_bitmap_csum_lo;
    211 	if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
    212 		csum |= ((__u32)gdp->bg_block_bitmap_csum_hi << 16);
    213 	return csum;
    214 }
    215 
    216 /*
    217  * Return the block bitmap block of a group
    218  */
    219 blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group)
    220 {
    221 	struct ext4_group_desc *gdp;
    222 
    223 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    224 	return gdp->bg_block_bitmap |
    225 		(ext2fs_has_feature_64bit(fs->super) ?
    226 		 (__u64)gdp->bg_block_bitmap_hi << 32 : 0);
    227 }
    228 
    229 /*
    230  * Set the block bitmap block of a group
    231  */
    232 void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
    233 {
    234 	struct ext4_group_desc *gdp;
    235 
    236 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    237 	gdp->bg_block_bitmap = blk;
    238 	if (ext2fs_has_feature_64bit(fs->super))
    239 		gdp->bg_block_bitmap_hi = (__u64) blk >> 32;
    240 }
    241 
    242 /*
    243  * Return the inode bitmap checksum of a group
    244  */
    245 __u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group)
    246 {
    247 	struct ext4_group_desc *gdp;
    248 	__u32 csum;
    249 
    250 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    251 	csum = gdp->bg_inode_bitmap_csum_lo;
    252 	if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
    253 		csum |= ((__u32)gdp->bg_inode_bitmap_csum_hi << 16);
    254 	return csum;
    255 }
    256 
    257 /*
    258  * Return the inode bitmap block of a group
    259  */
    260 blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group)
    261 {
    262 	struct ext4_group_desc *gdp;
    263 
    264 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    265 	return gdp->bg_inode_bitmap |
    266 		(ext2fs_has_feature_64bit(fs->super) ?
    267 		 (__u64) gdp->bg_inode_bitmap_hi << 32 : 0);
    268 }
    269 
    270 /*
    271  * Set the inode bitmap block of a group
    272  */
    273 void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
    274 {
    275 	struct ext4_group_desc *gdp;
    276 
    277 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    278 	gdp->bg_inode_bitmap = blk;
    279 	if (ext2fs_has_feature_64bit(fs->super))
    280 		gdp->bg_inode_bitmap_hi = (__u64) blk >> 32;
    281 }
    282 
    283 /*
    284  * Return the inode table block of a group
    285  */
    286 blk64_t ext2fs_inode_table_loc(ext2_filsys fs, dgrp_t group)
    287 {
    288 	struct ext4_group_desc *gdp;
    289 
    290 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    291 	return gdp->bg_inode_table |
    292 		(ext2fs_has_feature_64bit(fs->super) ?
    293 		 (__u64) gdp->bg_inode_table_hi << 32 : 0);
    294 }
    295 
    296 /*
    297  * Set the inode table block of a group
    298  */
    299 void ext2fs_inode_table_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
    300 {
    301 	struct ext4_group_desc *gdp;
    302 
    303 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    304 	gdp->bg_inode_table = blk;
    305 	if (ext2fs_has_feature_64bit(fs->super))
    306 		gdp->bg_inode_table_hi = (__u64) blk >> 32;
    307 }
    308 
    309 /*
    310  * Return the free blocks count of a group
    311  */
    312 __u32 ext2fs_bg_free_blocks_count(ext2_filsys fs, dgrp_t group)
    313 {
    314 	struct ext4_group_desc *gdp;
    315 
    316 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    317 	return gdp->bg_free_blocks_count |
    318 		(ext2fs_has_feature_64bit(fs->super) ?
    319 		 (__u32) gdp->bg_free_blocks_count_hi << 16 : 0);
    320 }
    321 
    322 /*
    323  * Set the free blocks count of a group
    324  */
    325 void ext2fs_bg_free_blocks_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
    326 {
    327 	struct ext4_group_desc *gdp;
    328 
    329 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    330 	gdp->bg_free_blocks_count = n;
    331 
    332 	if (ext2fs_has_feature_64bit(fs->super))
    333 		gdp->bg_free_blocks_count_hi = (__u32) n >> 16;
    334 }
    335 
    336 /*
    337  * Return the free inodes count of a group
    338  */
    339 __u32 ext2fs_bg_free_inodes_count(ext2_filsys fs, dgrp_t group)
    340 {
    341 	struct ext4_group_desc *gdp;
    342 
    343 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    344 	return gdp->bg_free_inodes_count |
    345 		(ext2fs_has_feature_64bit(fs->super) ?
    346 		 (__u32) gdp->bg_free_inodes_count_hi << 16 : 0);
    347 }
    348 
    349 /*
    350  * Set the free inodes count of a group
    351  */
    352 void ext2fs_bg_free_inodes_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
    353 {
    354 	struct ext4_group_desc *gdp;
    355 
    356 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    357 	gdp->bg_free_inodes_count = n;
    358 	if (ext2fs_has_feature_64bit(fs->super))
    359 		gdp->bg_free_inodes_count_hi = (__u32) n >> 16;
    360 }
    361 
    362 /*
    363  * Return the used dirs count of a group
    364  */
    365 __u32 ext2fs_bg_used_dirs_count(ext2_filsys fs, dgrp_t group)
    366 {
    367 	struct ext4_group_desc *gdp;
    368 
    369 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    370 	return gdp->bg_used_dirs_count |
    371 		(ext2fs_has_feature_64bit(fs->super) ?
    372 		 (__u32) gdp->bg_used_dirs_count_hi << 16 : 0);
    373 }
    374 
    375 /*
    376  * Set the used dirs count of a group
    377  */
    378 void ext2fs_bg_used_dirs_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
    379 {
    380 	struct ext4_group_desc *gdp;
    381 
    382 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    383 	gdp->bg_used_dirs_count = n;
    384 	if (ext2fs_has_feature_64bit(fs->super))
    385 		gdp->bg_used_dirs_count_hi = (__u32) n >> 16;
    386 }
    387 
    388 /*
    389  * Return the unused inodes count of a group
    390  */
    391 __u32 ext2fs_bg_itable_unused(ext2_filsys fs, dgrp_t group)
    392 {
    393 	struct ext4_group_desc *gdp;
    394 
    395 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    396 	return gdp->bg_itable_unused |
    397 		(ext2fs_has_feature_64bit(fs->super) ?
    398 		 (__u32) gdp->bg_itable_unused_hi << 16 : 0);
    399 }
    400 
    401 /*
    402  * Set the unused inodes count of a group
    403  */
    404 void ext2fs_bg_itable_unused_set(ext2_filsys fs, dgrp_t group, __u32 n)
    405 {
    406 	struct ext4_group_desc *gdp;
    407 
    408 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    409 	gdp->bg_itable_unused = n;
    410 	if (ext2fs_has_feature_64bit(fs->super))
    411 		gdp->bg_itable_unused_hi = (__u32) n >> 16;
    412 }
    413 
    414 /*
    415  * Get the flags for this block group
    416  */
    417 __u16 ext2fs_bg_flags(ext2_filsys fs, dgrp_t group)
    418 {
    419 	struct ext4_group_desc *gdp;
    420 
    421 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    422 	return gdp->bg_flags;
    423 }
    424 
    425 /*
    426  * Zero out the flags for this block group
    427  */
    428 void ext2fs_bg_flags_zap(ext2_filsys fs, dgrp_t group)
    429 {
    430 	struct ext4_group_desc *gdp;
    431 
    432 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    433 	gdp->bg_flags = 0;
    434 	return;
    435 }
    436 
    437 /*
    438  * Get the value of a particular flag for this block group
    439  */
    440 int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag)
    441 {
    442 	struct ext4_group_desc *gdp;
    443 
    444 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    445 	return gdp->bg_flags & bg_flag;
    446 }
    447 
    448 /*
    449  * Set a flag or set of flags for this block group
    450  */
    451 void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags)
    452 {
    453 	struct ext4_group_desc *gdp;
    454 
    455 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    456 	gdp->bg_flags |= bg_flags;
    457 	return;
    458 }
    459 
    460 /*
    461  * Clear a flag or set of flags for this block group
    462  */
    463 void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags)
    464 {
    465 	struct ext4_group_desc *gdp;
    466 
    467 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    468 	gdp->bg_flags &= ~bg_flags;
    469 	return;
    470 }
    471 
    472 /*
    473  * Get the checksum for this block group
    474  */
    475 __u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group)
    476 {
    477 	struct ext4_group_desc *gdp;
    478 
    479 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    480 	return gdp->bg_checksum;
    481 }
    482 
    483 /*
    484  * Set the checksum for this block group to a previously calculated value
    485  */
    486 void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum)
    487 {
    488 	struct ext4_group_desc *gdp;
    489 
    490 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
    491 	gdp->bg_checksum = checksum;
    492 	return;
    493 }
    494 
    495 /*
    496  * Get the acl block of a file
    497  */
    498 blk64_t ext2fs_file_acl_block(ext2_filsys fs, const struct ext2_inode *inode)
    499 {
    500 	blk64_t	blk = inode->i_file_acl;
    501 
    502 	if (fs && ext2fs_has_feature_64bit(fs->super))
    503 		blk |= ((__u64) inode->osd2.linux2.l_i_file_acl_high) << 32;
    504 	return blk;
    505 }
    506 
    507 /*
    508  * Set the acl block of a file
    509  */
    510 void ext2fs_file_acl_block_set(ext2_filsys fs, struct ext2_inode *inode,
    511 			       blk64_t blk)
    512 {
    513 	inode->i_file_acl = blk;
    514 	if (fs && ext2fs_has_feature_64bit(fs->super))
    515 		inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32;
    516 }
    517 
    518 /*
    519  * Set the size of the inode
    520  */
    521 errcode_t ext2fs_inode_size_set(ext2_filsys fs, struct ext2_inode *inode,
    522 				ext2_off64_t size)
    523 {
    524 	/* Only regular files get to be larger than 4GB */
    525 	if (!LINUX_S_ISREG(inode->i_mode) && (size >> 32))
    526 		return EXT2_ET_FILE_TOO_BIG;
    527 
    528 	/* If we're writing a large file, set the large_file flag */
    529 	if (LINUX_S_ISREG(inode->i_mode) &&
    530 	    ext2fs_needs_large_file_feature(size) &&
    531 	    (!ext2fs_has_feature_large_file(fs->super) ||
    532 	     fs->super->s_rev_level == EXT2_GOOD_OLD_REV)) {
    533 		ext2fs_set_feature_large_file(fs->super);
    534 		ext2fs_update_dynamic_rev(fs);
    535 		ext2fs_mark_super_dirty(fs);
    536 	}
    537 
    538 	inode->i_size = size & 0xffffffff;
    539 	inode->i_size_high = (size >> 32);
    540 
    541 	return 0;
    542 }
    543 
    544