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 ? EXT2_CLUSTER_SIZE(fs->super) >> 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 (EXT2_DESC_SIZE(fs->super) >= 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 (EXT2_DESC_SIZE(fs->super) >= 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