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@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 inode i_blocks in stat (512 byte) units 90 */ 91 blk64_t ext2fs_get_stat_i_blocks(ext2_filsys fs, 92 struct ext2_inode *inode) 93 { 94 blk64_t ret = inode->i_blocks; 95 96 if (ext2fs_has_feature_huge_file(fs->super)) { 97 ret += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32; 98 if (inode->i_flags & EXT4_HUGE_FILE_FL) 99 ret *= (fs->blocksize / 512); 100 } 101 return ret; 102 } 103 104 /* 105 * Return the fs block count 106 */ 107 blk64_t ext2fs_blocks_count(struct ext2_super_block *super) 108 { 109 return super->s_blocks_count | 110 (ext2fs_has_feature_64bit(super) ? 111 (__u64) super->s_blocks_count_hi << 32 : 0); 112 } 113 114 /* 115 * Set the fs block count 116 */ 117 void ext2fs_blocks_count_set(struct ext2_super_block *super, blk64_t blk) 118 { 119 super->s_blocks_count = blk; 120 if (ext2fs_has_feature_64bit(super)) 121 super->s_blocks_count_hi = (__u64) blk >> 32; 122 } 123 124 /* 125 * Add to the current fs block count 126 */ 127 void ext2fs_blocks_count_add(struct ext2_super_block *super, blk64_t blk) 128 { 129 blk64_t tmp; 130 tmp = ext2fs_blocks_count(super) + blk; 131 ext2fs_blocks_count_set(super, tmp); 132 } 133 134 /* 135 * Return the fs reserved block count 136 */ 137 blk64_t ext2fs_r_blocks_count(struct ext2_super_block *super) 138 { 139 return super->s_r_blocks_count | 140 (ext2fs_has_feature_64bit(super) ? 141 (__u64) super->s_r_blocks_count_hi << 32 : 0); 142 } 143 144 /* 145 * Set the fs reserved block count 146 */ 147 void ext2fs_r_blocks_count_set(struct ext2_super_block *super, blk64_t blk) 148 { 149 super->s_r_blocks_count = blk; 150 if (ext2fs_has_feature_64bit(super)) 151 super->s_r_blocks_count_hi = (__u64) blk >> 32; 152 } 153 154 /* 155 * Add to the current reserved fs block count 156 */ 157 void ext2fs_r_blocks_count_add(struct ext2_super_block *super, blk64_t blk) 158 { 159 blk64_t tmp; 160 tmp = ext2fs_r_blocks_count(super) + blk; 161 ext2fs_r_blocks_count_set(super, tmp); 162 } 163 164 /* 165 * Return the fs free block count 166 */ 167 blk64_t ext2fs_free_blocks_count(struct ext2_super_block *super) 168 { 169 return super->s_free_blocks_count | 170 (ext2fs_has_feature_64bit(super) ? 171 (__u64) super->s_free_blocks_hi << 32 : 0); 172 } 173 174 /* 175 * Set the fs free block count 176 */ 177 void ext2fs_free_blocks_count_set(struct ext2_super_block *super, blk64_t blk) 178 { 179 super->s_free_blocks_count = blk; 180 if (ext2fs_has_feature_64bit(super)) 181 super->s_free_blocks_hi = (__u64) blk >> 32; 182 } 183 184 /* 185 * Add to the current free fs block count 186 */ 187 void ext2fs_free_blocks_count_add(struct ext2_super_block *super, blk64_t blk) 188 { 189 blk64_t tmp; 190 tmp = ext2fs_free_blocks_count(super) + blk; 191 ext2fs_free_blocks_count_set(super, tmp); 192 } 193 194 /* 195 * Get a pointer to a block group descriptor. We need the explicit 196 * pointer to the group desc for code that swaps block group 197 * descriptors before writing them out, as it wants to make a copy and 198 * do the swap there. 199 */ 200 struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs, 201 struct opaque_ext2_group_desc *gdp, 202 dgrp_t group) 203 { 204 struct ext2_group_desc *ret_gdp; 205 errcode_t retval; 206 static char *buf = 0; 207 static int bufsize = 0; 208 blk64_t blk; 209 int desc_size = EXT2_DESC_SIZE(fs->super) & ~7; 210 int desc_per_blk = EXT2_DESC_PER_BLOCK(fs->super); 211 212 if (group > fs->group_desc_count) 213 return NULL; 214 if (gdp) 215 return (struct ext2_group_desc *)((char *)gdp + 216 group * desc_size); 217 /* 218 * If fs->group_desc wasn't read in when the file system was 219 * opened, then read it on demand here. 220 */ 221 if (bufsize < fs->blocksize) 222 ext2fs_free_mem(&buf); 223 if (!buf) { 224 retval = ext2fs_get_mem(fs->blocksize, &buf); 225 if (retval) 226 return NULL; 227 bufsize = fs->blocksize; 228 } 229 blk = ext2fs_descriptor_block_loc2(fs, fs->super->s_first_data_block, 230 group / desc_per_blk); 231 retval = io_channel_read_blk(fs->io, blk, 1, buf); 232 if (retval) 233 return NULL; 234 ret_gdp = (struct ext2_group_desc *) 235 (buf + ((group % desc_per_blk) * desc_size)); 236 #ifdef WORDS_BIGENDIAN 237 ext2fs_swap_group_desc2(fs, ret_gdp); 238 #endif 239 return ret_gdp; 240 } 241 242 /* Do the same but as an ext4 group desc for internal use here */ 243 static struct ext4_group_desc *ext4fs_group_desc(ext2_filsys fs, 244 struct opaque_ext2_group_desc *gdp, 245 dgrp_t group) 246 { 247 return (struct ext4_group_desc *)ext2fs_group_desc(fs, gdp, group); 248 } 249 250 /* 251 * Return the block bitmap checksum of a group 252 */ 253 __u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group) 254 { 255 struct ext4_group_desc *gdp; 256 __u32 csum; 257 258 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 259 csum = gdp->bg_block_bitmap_csum_lo; 260 if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) 261 csum |= ((__u32)gdp->bg_block_bitmap_csum_hi << 16); 262 return csum; 263 } 264 265 /* 266 * Return the block bitmap block of a group 267 */ 268 blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group) 269 { 270 struct ext4_group_desc *gdp; 271 272 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 273 return gdp->bg_block_bitmap | 274 (ext2fs_has_feature_64bit(fs->super) ? 275 (__u64)gdp->bg_block_bitmap_hi << 32 : 0); 276 } 277 278 /* 279 * Set the block bitmap block of a group 280 */ 281 void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk) 282 { 283 struct ext4_group_desc *gdp; 284 285 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 286 gdp->bg_block_bitmap = blk; 287 if (ext2fs_has_feature_64bit(fs->super)) 288 gdp->bg_block_bitmap_hi = (__u64) blk >> 32; 289 } 290 291 /* 292 * Return the inode bitmap checksum of a group 293 */ 294 __u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group) 295 { 296 struct ext4_group_desc *gdp; 297 __u32 csum; 298 299 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 300 csum = gdp->bg_inode_bitmap_csum_lo; 301 if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) 302 csum |= ((__u32)gdp->bg_inode_bitmap_csum_hi << 16); 303 return csum; 304 } 305 306 /* 307 * Return the inode bitmap block of a group 308 */ 309 blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group) 310 { 311 struct ext4_group_desc *gdp; 312 313 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 314 return gdp->bg_inode_bitmap | 315 (ext2fs_has_feature_64bit(fs->super) ? 316 (__u64) gdp->bg_inode_bitmap_hi << 32 : 0); 317 } 318 319 /* 320 * Set the inode bitmap block of a group 321 */ 322 void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk) 323 { 324 struct ext4_group_desc *gdp; 325 326 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 327 gdp->bg_inode_bitmap = blk; 328 if (ext2fs_has_feature_64bit(fs->super)) 329 gdp->bg_inode_bitmap_hi = (__u64) blk >> 32; 330 } 331 332 /* 333 * Return the inode table block of a group 334 */ 335 blk64_t ext2fs_inode_table_loc(ext2_filsys fs, dgrp_t group) 336 { 337 struct ext4_group_desc *gdp; 338 339 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 340 return gdp->bg_inode_table | 341 (ext2fs_has_feature_64bit(fs->super) ? 342 (__u64) gdp->bg_inode_table_hi << 32 : 0); 343 } 344 345 /* 346 * Set the inode table block of a group 347 */ 348 void ext2fs_inode_table_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk) 349 { 350 struct ext4_group_desc *gdp; 351 352 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 353 gdp->bg_inode_table = blk; 354 if (ext2fs_has_feature_64bit(fs->super)) 355 gdp->bg_inode_table_hi = (__u64) blk >> 32; 356 } 357 358 /* 359 * Return the free blocks count of a group 360 */ 361 __u32 ext2fs_bg_free_blocks_count(ext2_filsys fs, dgrp_t group) 362 { 363 struct ext4_group_desc *gdp; 364 365 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 366 return gdp->bg_free_blocks_count | 367 (ext2fs_has_feature_64bit(fs->super) ? 368 (__u32) gdp->bg_free_blocks_count_hi << 16 : 0); 369 } 370 371 /* 372 * Set the free blocks count of a group 373 */ 374 void ext2fs_bg_free_blocks_count_set(ext2_filsys fs, dgrp_t group, __u32 n) 375 { 376 struct ext4_group_desc *gdp; 377 378 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 379 gdp->bg_free_blocks_count = n; 380 381 if (ext2fs_has_feature_64bit(fs->super)) 382 gdp->bg_free_blocks_count_hi = (__u32) n >> 16; 383 } 384 385 /* 386 * Return the free inodes count of a group 387 */ 388 __u32 ext2fs_bg_free_inodes_count(ext2_filsys fs, dgrp_t group) 389 { 390 struct ext4_group_desc *gdp; 391 392 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 393 return gdp->bg_free_inodes_count | 394 (ext2fs_has_feature_64bit(fs->super) ? 395 (__u32) gdp->bg_free_inodes_count_hi << 16 : 0); 396 } 397 398 /* 399 * Set the free inodes count of a group 400 */ 401 void ext2fs_bg_free_inodes_count_set(ext2_filsys fs, dgrp_t group, __u32 n) 402 { 403 struct ext4_group_desc *gdp; 404 405 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 406 gdp->bg_free_inodes_count = n; 407 if (ext2fs_has_feature_64bit(fs->super)) 408 gdp->bg_free_inodes_count_hi = (__u32) n >> 16; 409 } 410 411 /* 412 * Return the used dirs count of a group 413 */ 414 __u32 ext2fs_bg_used_dirs_count(ext2_filsys fs, dgrp_t group) 415 { 416 struct ext4_group_desc *gdp; 417 418 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 419 return gdp->bg_used_dirs_count | 420 (ext2fs_has_feature_64bit(fs->super) ? 421 (__u32) gdp->bg_used_dirs_count_hi << 16 : 0); 422 } 423 424 /* 425 * Set the used dirs count of a group 426 */ 427 void ext2fs_bg_used_dirs_count_set(ext2_filsys fs, dgrp_t group, __u32 n) 428 { 429 struct ext4_group_desc *gdp; 430 431 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 432 gdp->bg_used_dirs_count = n; 433 if (ext2fs_has_feature_64bit(fs->super)) 434 gdp->bg_used_dirs_count_hi = (__u32) n >> 16; 435 } 436 437 /* 438 * Return the unused inodes count of a group 439 */ 440 __u32 ext2fs_bg_itable_unused(ext2_filsys fs, dgrp_t group) 441 { 442 struct ext4_group_desc *gdp; 443 444 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 445 return gdp->bg_itable_unused | 446 (ext2fs_has_feature_64bit(fs->super) ? 447 (__u32) gdp->bg_itable_unused_hi << 16 : 0); 448 } 449 450 /* 451 * Set the unused inodes count of a group 452 */ 453 void ext2fs_bg_itable_unused_set(ext2_filsys fs, dgrp_t group, __u32 n) 454 { 455 struct ext4_group_desc *gdp; 456 457 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 458 gdp->bg_itable_unused = n; 459 if (ext2fs_has_feature_64bit(fs->super)) 460 gdp->bg_itable_unused_hi = (__u32) n >> 16; 461 } 462 463 /* 464 * Get the flags for this block group 465 */ 466 __u16 ext2fs_bg_flags(ext2_filsys fs, dgrp_t group) 467 { 468 struct ext4_group_desc *gdp; 469 470 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 471 return gdp->bg_flags; 472 } 473 474 /* 475 * Zero out the flags for this block group 476 */ 477 void ext2fs_bg_flags_zap(ext2_filsys fs, dgrp_t group) 478 { 479 struct ext4_group_desc *gdp; 480 481 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 482 gdp->bg_flags = 0; 483 return; 484 } 485 486 /* 487 * Get the value of a particular flag for this block group 488 */ 489 int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag) 490 { 491 struct ext4_group_desc *gdp; 492 493 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 494 return gdp->bg_flags & bg_flag; 495 } 496 497 /* 498 * Set a flag or set of flags for this block group 499 */ 500 void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags) 501 { 502 struct ext4_group_desc *gdp; 503 504 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 505 gdp->bg_flags |= bg_flags; 506 return; 507 } 508 509 /* 510 * Clear a flag or set of flags for this block group 511 */ 512 void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags) 513 { 514 struct ext4_group_desc *gdp; 515 516 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 517 gdp->bg_flags &= ~bg_flags; 518 return; 519 } 520 521 /* 522 * Get the checksum for this block group 523 */ 524 __u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group) 525 { 526 struct ext4_group_desc *gdp; 527 528 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 529 return gdp->bg_checksum; 530 } 531 532 /* 533 * Set the checksum for this block group to a previously calculated value 534 */ 535 void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum) 536 { 537 struct ext4_group_desc *gdp; 538 539 gdp = ext4fs_group_desc(fs, fs->group_desc, group); 540 gdp->bg_checksum = checksum; 541 return; 542 } 543 544 /* 545 * Get the acl block of a file 546 */ 547 blk64_t ext2fs_file_acl_block(ext2_filsys fs, const struct ext2_inode *inode) 548 { 549 blk64_t blk = inode->i_file_acl; 550 551 if (fs && ext2fs_has_feature_64bit(fs->super)) 552 blk |= ((__u64) inode->osd2.linux2.l_i_file_acl_high) << 32; 553 return blk; 554 } 555 556 /* 557 * Set the acl block of a file 558 */ 559 void ext2fs_file_acl_block_set(ext2_filsys fs, struct ext2_inode *inode, 560 blk64_t blk) 561 { 562 inode->i_file_acl = blk; 563 if (fs && ext2fs_has_feature_64bit(fs->super)) 564 inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32; 565 } 566 567 /* 568 * Set the size of the inode 569 */ 570 errcode_t ext2fs_inode_size_set(ext2_filsys fs, struct ext2_inode *inode, 571 ext2_off64_t size) 572 { 573 if (size < 0) 574 return EINVAL; 575 576 /* If writing a large inode, set the large_file or large_dir flag */ 577 if (ext2fs_needs_large_file_feature(size)) { 578 int dirty_sb = 0; 579 580 if (LINUX_S_ISREG(inode->i_mode)) { 581 if (!ext2fs_has_feature_large_file(fs->super)) { 582 ext2fs_set_feature_large_file(fs->super); 583 dirty_sb = 1; 584 } 585 } else if (LINUX_S_ISDIR(inode->i_mode)) { 586 if (!ext2fs_has_feature_largedir(fs->super)) { 587 ext2fs_set_feature_largedir(fs->super); 588 dirty_sb = 1; 589 } 590 } else { 591 /* Only regular files get to be larger than 4GB */ 592 return EXT2_ET_FILE_TOO_BIG; 593 } 594 if (dirty_sb) { 595 if (fs->super->s_rev_level == EXT2_GOOD_OLD_REV) 596 ext2fs_update_dynamic_rev(fs); 597 ext2fs_mark_super_dirty(fs); 598 } 599 } 600 601 inode->i_size = size & 0xffffffff; 602 inode->i_size_high = (size >> 32); 603 604 return 0; 605 } 606