Coverage Report

Created: 2022-11-24 06:30

/src/e2fsprogs/lib/ext2fs/blknum.c
Line
Count
Source (jump to first uncovered line)
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
0
{
22
0
  return (blk - fs->super->s_first_data_block) /
23
0
    fs->super->s_blocks_per_group;
24
0
}
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
17.1M
{
31
17.1M
  return fs->super->s_first_data_block +
32
17.1M
    EXT2_GROUPS_TO_BLOCKS(fs->super, group);
33
17.1M
}
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
0
{
40
0
  return (group == fs->group_desc_count - 1 ?
41
0
    ext2fs_blocks_count(fs->super) - 1 :
42
0
    ext2fs_group_first_block2(fs, group) +
43
0
      (fs->super->s_blocks_per_group - 1));
44
0
}
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
262k
{
51
262k
  int num_blocks;
52
53
262k
  if (group == fs->group_desc_count - 1) {
54
221
    num_blocks = (ext2fs_blocks_count(fs->super) -
55
221
        fs->super->s_first_data_block) %
56
221
            fs->super->s_blocks_per_group;
57
221
    if (!num_blocks)
58
89
      num_blocks = fs->super->s_blocks_per_group;
59
221
  } else
60
262k
    num_blocks = fs->super->s_blocks_per_group;
61
62
262k
  return num_blocks;
63
262k
}
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
0
{
71
0
  return (inode->i_blocks |
72
0
    (ext2fs_has_feature_huge_file(fs->super) ?
73
0
     (__u64) inode->osd2.linux2.l_i_blocks_hi << 32 : 0)) -
74
0
    (inode->i_file_acl ? EXT2_CLUSTER_SIZE(fs->super) >> 9 : 0);
75
0
}
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
0
{
83
0
  return (inode->i_blocks |
84
0
    (ext2fs_has_feature_huge_file(fs->super) ?
85
0
     (__u64)inode->osd2.linux2.l_i_blocks_hi << 32 : 0));
86
0
}
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
0
{
94
0
  blk64_t ret = inode->i_blocks;
95
96
0
  if (ext2fs_has_feature_huge_file(fs->super)) {
97
0
    ret += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
98
0
    if (inode->i_flags & EXT4_HUGE_FILE_FL)
99
0
      ret *= (fs->blocksize / 512);
100
0
  }
101
0
  return ret;
102
0
}
103
104
/*
105
 * Return the fs block count
106
 */
107
blk64_t ext2fs_blocks_count(struct ext2_super_block *super)
108
1.14M
{
109
1.14M
  return super->s_blocks_count |
110
1.14M
    (ext2fs_has_feature_64bit(super) ?
111
1.12M
    (__u64) super->s_blocks_count_hi << 32 : 0);
112
1.14M
}
113
114
/*
115
 * Set the fs block count
116
 */
117
void ext2fs_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
118
0
{
119
0
  super->s_blocks_count = blk;
120
0
  if (ext2fs_has_feature_64bit(super))
121
0
    super->s_blocks_count_hi = (__u64) blk >> 32;
122
0
}
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
0
{
129
0
  blk64_t tmp;
130
0
  tmp = ext2fs_blocks_count(super) + blk;
131
0
  ext2fs_blocks_count_set(super, tmp);
132
0
}
133
134
/*
135
 * Return the fs reserved block count
136
 */
137
blk64_t ext2fs_r_blocks_count(struct ext2_super_block *super)
138
0
{
139
0
  return super->s_r_blocks_count |
140
0
    (ext2fs_has_feature_64bit(super) ?
141
0
    (__u64) super->s_r_blocks_count_hi << 32 : 0);
142
0
}
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
0
{
149
0
  super->s_r_blocks_count = blk;
150
0
  if (ext2fs_has_feature_64bit(super))
151
0
    super->s_r_blocks_count_hi = (__u64) blk >> 32;
152
0
}
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
0
{
159
0
  blk64_t tmp;
160
0
  tmp = ext2fs_r_blocks_count(super) + blk;
161
0
  ext2fs_r_blocks_count_set(super, tmp);
162
0
}
163
164
/*
165
 * Return the fs free block count
166
 */
167
blk64_t ext2fs_free_blocks_count(struct ext2_super_block *super)
168
0
{
169
0
  return super->s_free_blocks_count |
170
0
    (ext2fs_has_feature_64bit(super) ?
171
0
    (__u64) super->s_free_blocks_hi << 32 : 0);
172
0
}
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
0
{
179
0
  super->s_free_blocks_count = blk;
180
0
  if (ext2fs_has_feature_64bit(super))
181
0
    super->s_free_blocks_hi = (__u64) blk >> 32;
182
0
}
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
0
{
189
0
  blk64_t tmp;
190
0
  tmp = ext2fs_free_blocks_count(super) + blk;
191
0
  ext2fs_free_blocks_count_set(super, tmp);
192
0
}
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
2.07M
{
204
2.07M
  struct ext2_group_desc *ret_gdp;
205
2.07M
  errcode_t retval;
206
2.07M
  static char *buf = 0;
207
2.07M
  static unsigned bufsize = 0;
208
2.07M
  blk64_t   blk;
209
2.07M
  int   desc_size = EXT2_DESC_SIZE(fs->super) & ~7;
210
2.07M
  int   desc_per_blk = EXT2_DESC_PER_BLOCK(fs->super);
211
212
2.07M
  if (group > fs->group_desc_count)
213
0
    return NULL;
214
2.07M
  if (gdp)
215
2.07M
    return (struct ext2_group_desc *)((char *)gdp +
216
2.07M
              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
0
  if (bufsize < fs->blocksize)
222
0
    ext2fs_free_mem(&buf);
223
0
  if (!buf) {
224
0
    retval = ext2fs_get_mem(fs->blocksize, &buf);
225
0
    if (retval)
226
0
      return NULL;
227
0
    bufsize = fs->blocksize;
228
0
  }
229
0
  blk = ext2fs_descriptor_block_loc2(fs, fs->super->s_first_data_block,
230
0
             group / desc_per_blk);
231
0
  retval = io_channel_read_blk(fs->io, blk, 1, buf);
232
0
  if (retval)
233
0
    return NULL;
234
0
  ret_gdp = (struct ext2_group_desc *)
235
0
    (buf + ((group % desc_per_blk) * desc_size));
236
#ifdef WORDS_BIGENDIAN
237
  ext2fs_swap_group_desc2(fs, ret_gdp);
238
#endif
239
0
  return ret_gdp;
240
0
}
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
1.91M
{
247
1.91M
  return (struct ext4_group_desc *)ext2fs_group_desc(fs, gdp, group);
248
1.91M
}
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
0
{
255
0
  struct ext4_group_desc *gdp;
256
0
  __u32 csum;
257
258
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
259
0
  csum = gdp->bg_block_bitmap_csum_lo;
260
0
  if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
261
0
    csum |= ((__u32)gdp->bg_block_bitmap_csum_hi << 16);
262
0
  return csum;
263
0
}
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
683k
{
270
683k
  struct ext4_group_desc *gdp;
271
272
683k
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
273
683k
  return gdp->bg_block_bitmap |
274
683k
    (ext2fs_has_feature_64bit(fs->super) ?
275
673k
     (__u64)gdp->bg_block_bitmap_hi << 32 : 0);
276
683k
}
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
0
{
283
0
  struct ext4_group_desc *gdp;
284
285
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
286
0
  gdp->bg_block_bitmap = blk;
287
0
  if (ext2fs_has_feature_64bit(fs->super))
288
0
    gdp->bg_block_bitmap_hi = (__u64) blk >> 32;
289
0
}
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
0
{
296
0
  struct ext4_group_desc *gdp;
297
0
  __u32 csum;
298
299
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
300
0
  csum = gdp->bg_inode_bitmap_csum_lo;
301
0
  if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
302
0
    csum |= ((__u32)gdp->bg_inode_bitmap_csum_hi << 16);
303
0
  return csum;
304
0
}
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
293k
{
311
293k
  struct ext4_group_desc *gdp;
312
313
293k
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
314
293k
  return gdp->bg_inode_bitmap |
315
293k
    (ext2fs_has_feature_64bit(fs->super) ?
316
289k
     (__u64) gdp->bg_inode_bitmap_hi << 32 : 0);
317
293k
}
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
0
{
324
0
  struct ext4_group_desc *gdp;
325
326
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
327
0
  gdp->bg_inode_bitmap = blk;
328
0
  if (ext2fs_has_feature_64bit(fs->super))
329
0
    gdp->bg_inode_bitmap_hi = (__u64) blk >> 32;
330
0
}
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
265k
{
337
265k
  struct ext4_group_desc *gdp;
338
339
265k
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
340
265k
  return gdp->bg_inode_table |
341
265k
    (ext2fs_has_feature_64bit(fs->super) ?
342
261k
     (__u64) gdp->bg_inode_table_hi << 32 : 0);
343
265k
}
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
0
{
350
0
  struct ext4_group_desc *gdp;
351
352
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
353
0
  gdp->bg_inode_table = blk;
354
0
  if (ext2fs_has_feature_64bit(fs->super))
355
0
    gdp->bg_inode_table_hi = (__u64) blk >> 32;
356
0
}
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
0
{
363
0
  struct ext4_group_desc *gdp;
364
365
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
366
0
  return gdp->bg_free_blocks_count |
367
0
    (ext2fs_has_feature_64bit(fs->super) ?
368
0
     (__u32) gdp->bg_free_blocks_count_hi << 16 : 0);
369
0
}
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
0
{
376
0
  struct ext4_group_desc *gdp;
377
378
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
379
0
  gdp->bg_free_blocks_count = n;
380
381
0
  if (ext2fs_has_feature_64bit(fs->super))
382
0
    gdp->bg_free_blocks_count_hi = (__u32) n >> 16;
383
0
}
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
0
{
390
0
  struct ext4_group_desc *gdp;
391
392
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
393
0
  return gdp->bg_free_inodes_count |
394
0
    (ext2fs_has_feature_64bit(fs->super) ?
395
0
     (__u32) gdp->bg_free_inodes_count_hi << 16 : 0);
396
0
}
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
0
{
403
0
  struct ext4_group_desc *gdp;
404
405
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
406
0
  gdp->bg_free_inodes_count = n;
407
0
  if (ext2fs_has_feature_64bit(fs->super))
408
0
    gdp->bg_free_inodes_count_hi = (__u32) n >> 16;
409
0
}
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
0
{
416
0
  struct ext4_group_desc *gdp;
417
418
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
419
0
  return gdp->bg_used_dirs_count |
420
0
    (ext2fs_has_feature_64bit(fs->super) ?
421
0
     (__u32) gdp->bg_used_dirs_count_hi << 16 : 0);
422
0
}
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
0
{
429
0
  struct ext4_group_desc *gdp;
430
431
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
432
0
  gdp->bg_used_dirs_count = n;
433
0
  if (ext2fs_has_feature_64bit(fs->super))
434
0
    gdp->bg_used_dirs_count_hi = (__u32) n >> 16;
435
0
}
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
0
{
442
0
  struct ext4_group_desc *gdp;
443
444
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
445
0
  return gdp->bg_itable_unused |
446
0
    (ext2fs_has_feature_64bit(fs->super) ?
447
0
     (__u32) gdp->bg_itable_unused_hi << 16 : 0);
448
0
}
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
0
{
455
0
  struct ext4_group_desc *gdp;
456
457
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
458
0
  gdp->bg_itable_unused = n;
459
0
  if (ext2fs_has_feature_64bit(fs->super))
460
0
    gdp->bg_itable_unused_hi = (__u32) n >> 16;
461
0
}
462
463
/*
464
 * Get the flags for this block group
465
 */
466
__u16 ext2fs_bg_flags(ext2_filsys fs, dgrp_t group)
467
0
{
468
0
  struct ext4_group_desc *gdp;
469
470
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
471
0
  return gdp->bg_flags;
472
0
}
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
0
{
479
0
  struct ext4_group_desc *gdp;
480
481
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
482
0
  gdp->bg_flags = 0;
483
0
  return;
484
0
}
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
508k
{
491
508k
  struct ext4_group_desc *gdp;
492
493
508k
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
494
508k
  return gdp->bg_flags & bg_flag;
495
508k
}
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
0
{
502
0
  struct ext4_group_desc *gdp;
503
504
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
505
0
  gdp->bg_flags |= bg_flags;
506
0
  return;
507
0
}
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
0
{
514
0
  struct ext4_group_desc *gdp;
515
516
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
517
0
  gdp->bg_flags &= ~bg_flags;
518
0
  return;
519
0
}
520
521
/*
522
 * Get the checksum for this block group
523
 */
524
__u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group)
525
162k
{
526
162k
  struct ext4_group_desc *gdp;
527
528
162k
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
529
162k
  return gdp->bg_checksum;
530
162k
}
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
0
{
537
0
  struct ext4_group_desc *gdp;
538
539
0
  gdp = ext4fs_group_desc(fs, fs->group_desc, group);
540
0
  gdp->bg_checksum = checksum;
541
0
  return;
542
0
}
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
0
{
549
0
  blk64_t blk = inode->i_file_acl;
550
551
0
  if (fs && ext2fs_has_feature_64bit(fs->super))
552
0
    blk |= ((__u64) inode->osd2.linux2.l_i_file_acl_high) << 32;
553
0
  return blk;
554
0
}
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
0
{
562
0
  inode->i_file_acl = blk;
563
0
  if (fs && ext2fs_has_feature_64bit(fs->super))
564
0
    inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32;
565
0
}
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
0
{
573
0
  if (size < 0)
574
0
    return EINVAL;
575
576
  /* If writing a large inode, set the large_file or large_dir flag */
577
0
  if (ext2fs_needs_large_file_feature(size)) {
578
0
    int dirty_sb = 0;
579
580
0
    if (LINUX_S_ISREG(inode->i_mode)) {
581
0
      if (!ext2fs_has_feature_large_file(fs->super)) {
582
0
        ext2fs_set_feature_large_file(fs->super);
583
0
        dirty_sb = 1;
584
0
      }
585
0
    } else if (LINUX_S_ISDIR(inode->i_mode)) {
586
0
      if (!ext2fs_has_feature_largedir(fs->super)) {
587
0
        ext2fs_set_feature_largedir(fs->super);
588
0
        dirty_sb = 1;
589
0
      }
590
0
    } else {
591
      /* Only regular files get to be larger than 4GB */
592
0
      return EXT2_ET_FILE_TOO_BIG;
593
0
    }
594
0
    if (dirty_sb) {
595
0
      if (fs->super->s_rev_level == EXT2_GOOD_OLD_REV)
596
0
        ext2fs_update_dynamic_rev(fs);
597
0
      ext2fs_mark_super_dirty(fs);
598
0
    }
599
0
  }
600
601
0
  inode->i_size = size & 0xffffffff;
602
0
  inode->i_size_high = (size >> 32);
603
604
0
  return 0;
605
0
}
606