Coverage Report

Created: 2022-11-24 06:30

/src/e2fsprogs/lib/ext2fs/gen_bitmap64.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * gen_bitmap64.c --- routines to read, write, and manipulate the new qinode and
3
 * block bitmaps.
4
 *
5
 * Copyright (C) 2007, 2008 Theodore Ts'o.
6
 *
7
 * %Begin-Header%
8
 * This file may be redistributed under the terms of the GNU Public
9
 * License.
10
 * %End-Header%
11
 */
12
13
#include "config.h"
14
#include <stdio.h>
15
#include <string.h>
16
#if HAVE_UNISTD_H
17
#include <unistd.h>
18
#endif
19
#include <fcntl.h>
20
#include <time.h>
21
#include <errno.h>
22
#if HAVE_SYS_STAT_H
23
#include <sys/stat.h>
24
#endif
25
#if HAVE_SYS_TYPES_H
26
#include <sys/types.h>
27
#endif
28
#ifdef HAVE_SYS_TIME_H
29
#include <sys/time.h>
30
#endif
31
32
#include "ext2_fs.h"
33
#include "ext2fsP.h"
34
#include "bmap64.h"
35
36
/*
37
 * Design of 64-bit bitmaps
38
 *
39
 * In order maintain ABI compatibility with programs that don't
40
 * understand about 64-bit blocks/inodes,
41
 * ext2fs_allocate_inode_bitmap() and ext2fs_allocate_block_bitmap()
42
 * will create old-style bitmaps unless the application passes the
43
 * flag EXT2_FLAG_64BITS to ext2fs_open().  If this flag is
44
 * passed, then we know the application has been recompiled, so we can
45
 * use the new-style bitmaps.  If it is not passed, we have to return
46
 * an error if trying to open a filesystem which needs 64-bit bitmaps.
47
 *
48
 * The new bitmaps use a new set of structure magic numbers, so that
49
 * both the old-style and new-style interfaces can identify which
50
 * version of the data structure was used.  Both the old-style and
51
 * new-style interfaces will support either type of bitmap, although
52
 * of course 64-bit operation will only be possible when both the
53
 * new-style interface and the new-style bitmap are used.
54
 *
55
 * For example, the new bitmap interfaces will check the structure
56
 * magic numbers and so will be able to detect old-stype bitmap.  If
57
 * they see an old-style bitmap, they will pass it to the gen_bitmap.c
58
 * functions for handling.  The same will be true for the old
59
 * interfaces as well.
60
 *
61
 * The new-style interfaces will have several different back-end
62
 * implementations, so we can support different encodings that are
63
 * appropriate for different applications.  In general the default
64
 * should be whatever makes sense, and what the application/library
65
 * will use.  However, e2fsck may need specialized implementations for
66
 * its own uses.  For example, when doing parent directory pointer
67
 * loop detections in pass 3, the bitmap will *always* be sparse, so
68
 * e2fsck can request an encoding which is optimized for that.
69
 */
70
71
static void warn_bitmap(ext2fs_generic_bitmap_64 bitmap,
72
      int code, __u64 arg)
73
0
{
74
0
#ifndef OMIT_COM_ERR
75
0
  if (bitmap->description)
76
0
    com_err(0, bitmap->base_error_code+code,
77
0
      "#%llu for %s", (unsigned long long) arg,
78
0
      bitmap->description);
79
0
  else
80
0
    com_err(0, bitmap->base_error_code + code, "#%llu",
81
0
      (unsigned long long) arg);
82
0
#endif
83
0
}
84
85
#ifdef ENABLE_BMAP_STATS_OPS
86
#define INC_STAT(map, name) map->stats.name
87
#else
88
0
#define INC_STAT(map, name) ;;
89
#endif
90
91
92
errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
93
            int type, __u64 start, __u64 end,
94
            __u64 real_end,
95
            const char *descr,
96
            ext2fs_generic_bitmap *ret)
97
0
{
98
0
  ext2fs_generic_bitmap_64 bitmap;
99
0
  struct ext2_bitmap_ops  *ops;
100
0
  ext2_ino_t num_dirs;
101
0
  errcode_t retval;
102
103
0
  if (!type)
104
0
    type = EXT2FS_BMAP64_BITARRAY;
105
106
0
  switch (type) {
107
0
  case EXT2FS_BMAP64_BITARRAY:
108
0
    ops = &ext2fs_blkmap64_bitarray;
109
0
    break;
110
0
  case EXT2FS_BMAP64_RBTREE:
111
0
    ops = &ext2fs_blkmap64_rbtree;
112
0
    break;
113
0
  case EXT2FS_BMAP64_AUTODIR:
114
0
    retval = ext2fs_get_num_dirs(fs, &num_dirs);
115
0
    if (retval || num_dirs > (fs->super->s_inodes_count / 320))
116
0
      ops = &ext2fs_blkmap64_bitarray;
117
0
    else
118
0
      ops = &ext2fs_blkmap64_rbtree;
119
0
    break;
120
0
  default:
121
0
    return EINVAL;
122
0
  }
123
124
0
  retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64),
125
0
            &bitmap);
126
0
  if (retval)
127
0
    return retval;
128
129
0
#ifdef ENABLE_BMAP_STATS
130
0
  if (gettimeofday(&bitmap->stats.created,
131
0
       (struct timezone *) NULL) == -1) {
132
0
    perror("gettimeofday");
133
0
    ext2fs_free_mem(&bitmap);
134
0
    return 1;
135
0
  }
136
0
  bitmap->stats.type = type;
137
0
#endif
138
139
  /* XXX factor out, repeated in copy_bmap */
140
0
  bitmap->magic = magic;
141
0
  bitmap->fs = fs;
142
0
  bitmap->start = start;
143
0
  bitmap->end = end;
144
0
  bitmap->real_end = real_end;
145
0
  bitmap->bitmap_ops = ops;
146
0
  bitmap->cluster_bits = 0;
147
0
  switch (magic) {
148
0
  case EXT2_ET_MAGIC_INODE_BITMAP64:
149
0
    bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
150
0
    break;
151
0
  case EXT2_ET_MAGIC_BLOCK_BITMAP64:
152
0
    bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
153
0
    bitmap->cluster_bits = fs->cluster_ratio_bits;
154
0
    break;
155
0
  default:
156
0
    bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
157
0
  }
158
0
  if (descr) {
159
0
    retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
160
0
    if (retval) {
161
0
      ext2fs_free_mem(&bitmap);
162
0
      return retval;
163
0
    }
164
0
    strcpy(bitmap->description, descr);
165
0
  } else
166
0
    bitmap->description = 0;
167
168
0
  retval = bitmap->bitmap_ops->new_bmap(fs, bitmap);
169
0
  if (retval) {
170
0
    ext2fs_free_mem(&bitmap->description);
171
0
    ext2fs_free_mem(&bitmap);
172
0
    return retval;
173
0
  }
174
175
0
  *ret = (ext2fs_generic_bitmap) bitmap;
176
0
  return 0;
177
0
}
178
179
#ifdef ENABLE_BMAP_STATS
180
static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap_64 bitmap)
181
0
{
182
0
  struct ext2_bmap_statistics *stats = &bitmap->stats;
183
#ifdef ENABLE_BMAP_STATS_OPS
184
  float mark_seq_perc = 0.0, test_seq_perc = 0.0;
185
  float mark_back_perc = 0.0, test_back_perc = 0.0;
186
#endif
187
0
  double inuse;
188
0
  struct timeval now;
189
190
#ifdef ENABLE_BMAP_STATS_OPS
191
  if (stats->test_count) {
192
    test_seq_perc = ((float)stats->test_seq /
193
         stats->test_count) * 100;
194
    test_back_perc = ((float)stats->test_back /
195
          stats->test_count) * 100;
196
  }
197
198
  if (stats->mark_count) {
199
    mark_seq_perc = ((float)stats->mark_seq /
200
         stats->mark_count) * 100;
201
    mark_back_perc = ((float)stats->mark_back /
202
          stats->mark_count) * 100;
203
  }
204
#endif
205
206
0
  if (gettimeofday(&now, (struct timezone *) NULL) == -1) {
207
0
    perror("gettimeofday");
208
0
    return;
209
0
  }
210
211
0
  inuse = (double) now.tv_sec + \
212
0
    (((double) now.tv_usec) * 0.000001);
213
0
  inuse -= (double) stats->created.tv_sec + \
214
0
    (((double) stats->created.tv_usec) * 0.000001);
215
216
0
  fprintf(stderr, "\n[+] %s bitmap (type %d)\n", bitmap->description,
217
0
    stats->type);
218
0
  fprintf(stderr, "=================================================\n");
219
#ifdef ENABLE_BMAP_STATS_OPS
220
  fprintf(stderr, "%16llu bits long\n",
221
    bitmap->real_end - bitmap->start);
222
  fprintf(stderr, "%16lu copy_bmap\n%16lu resize_bmap\n",
223
    stats->copy_count, stats->resize_count);
224
  fprintf(stderr, "%16lu mark bmap\n%16lu unmark_bmap\n",
225
    stats->mark_count, stats->unmark_count);
226
  fprintf(stderr, "%16lu test_bmap\n%16lu mark_bmap_extent\n",
227
    stats->test_count, stats->mark_ext_count);
228
  fprintf(stderr, "%16lu unmark_bmap_extent\n"
229
    "%16lu test_clear_bmap_extent\n",
230
    stats->unmark_ext_count, stats->test_ext_count);
231
  fprintf(stderr, "%16lu set_bmap_range\n%16lu set_bmap_range\n",
232
    stats->set_range_count, stats->get_range_count);
233
  fprintf(stderr, "%16lu clear_bmap\n%16lu contiguous bit test (%.2f%%)\n",
234
    stats->clear_count, stats->test_seq, test_seq_perc);
235
  fprintf(stderr, "%16lu contiguous bit mark (%.2f%%)\n"
236
    "%16llu bits tested backwards (%.2f%%)\n",
237
    stats->mark_seq, mark_seq_perc,
238
    stats->test_back, test_back_perc);
239
  fprintf(stderr, "%16llu bits marked backwards (%.2f%%)\n"
240
    "%16.2f seconds in use\n",
241
    stats->mark_back, mark_back_perc, inuse);
242
#endif /* ENABLE_BMAP_STATS_OPS */
243
0
}
244
#endif
245
246
void ext2fs_free_generic_bmap(ext2fs_generic_bitmap gen_bmap)
247
439
{
248
439
  ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
249
250
439
  if (!bmap)
251
0
    return;
252
253
439
  if (EXT2FS_IS_32_BITMAP(bmap)) {
254
439
    ext2fs_free_generic_bitmap(gen_bmap);
255
439
    return;
256
439
  }
257
258
0
  if (!EXT2FS_IS_64_BITMAP(bmap))
259
0
    return;
260
261
0
#ifdef ENABLE_BMAP_STATS
262
0
  if (getenv("E2FSPROGS_BITMAP_STATS")) {
263
0
    ext2fs_print_bmap_statistics(bmap);
264
0
    bmap->bitmap_ops->print_stats(bmap);
265
0
  }
266
0
#endif
267
268
0
  bmap->bitmap_ops->free_bmap(bmap);
269
270
0
  if (bmap->description) {
271
0
    ext2fs_free_mem(&bmap->description);
272
0
    bmap->description = 0;
273
0
  }
274
0
  bmap->magic = 0;
275
0
  ext2fs_free_mem(&bmap);
276
0
}
277
278
errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap gen_src,
279
           ext2fs_generic_bitmap *dest)
280
0
{
281
0
  ext2fs_generic_bitmap_64 src = (ext2fs_generic_bitmap_64) gen_src;
282
0
  char *descr, *new_descr;
283
0
  ext2fs_generic_bitmap_64 new_bmap;
284
0
  errcode_t retval;
285
286
0
  if (!src)
287
0
    return EINVAL;
288
289
0
  if (EXT2FS_IS_32_BITMAP(src))
290
0
    return ext2fs_copy_generic_bitmap(gen_src, dest);
291
292
0
  if (!EXT2FS_IS_64_BITMAP(src))
293
0
    return EINVAL;
294
295
  /* Allocate a new bitmap struct */
296
0
  retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64),
297
0
            &new_bmap);
298
0
  if (retval)
299
0
    return retval;
300
301
302
#ifdef ENABLE_BMAP_STATS_OPS
303
  src->stats.copy_count++;
304
#endif
305
0
#ifdef ENABLE_BMAP_STATS
306
0
  if (gettimeofday(&new_bmap->stats.created,
307
0
       (struct timezone *) NULL) == -1) {
308
0
    perror("gettimeofday");
309
0
    ext2fs_free_mem(&new_bmap);
310
0
    return 1;
311
0
  }
312
0
  new_bmap->stats.type = src->stats.type;
313
0
#endif
314
315
  /* Copy all the high-level parts over */
316
0
  new_bmap->magic = src->magic;
317
0
  new_bmap->fs = src->fs;
318
0
  new_bmap->start = src->start;
319
0
  new_bmap->end = src->end;
320
0
  new_bmap->real_end = src->real_end;
321
0
  new_bmap->bitmap_ops = src->bitmap_ops;
322
0
  new_bmap->base_error_code = src->base_error_code;
323
0
  new_bmap->cluster_bits = src->cluster_bits;
324
325
0
  descr = src->description;
326
0
  if (descr) {
327
0
    retval = ext2fs_get_mem(strlen(descr)+10, &new_descr);
328
0
    if (retval) {
329
0
      ext2fs_free_mem(&new_bmap);
330
0
      return retval;
331
0
    }
332
0
    strcpy(new_descr, "copy of ");
333
0
    strcat(new_descr, descr);
334
0
    new_bmap->description = new_descr;
335
0
  }
336
337
0
  retval = src->bitmap_ops->copy_bmap(src, new_bmap);
338
0
  if (retval) {
339
0
    ext2fs_free_mem(&new_bmap->description);
340
0
    ext2fs_free_mem(&new_bmap);
341
0
    return retval;
342
0
  }
343
344
0
  *dest = (ext2fs_generic_bitmap) new_bmap;
345
346
0
  return 0;
347
0
}
348
349
errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap gen_bmap,
350
             __u64 new_end,
351
             __u64 new_real_end)
352
0
{
353
0
  ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
354
355
0
  if (!bmap)
356
0
    return EINVAL;
357
358
0
  if (EXT2FS_IS_32_BITMAP(bmap))
359
0
    return ext2fs_resize_generic_bitmap(gen_bmap->magic, new_end,
360
0
                new_real_end, gen_bmap);
361
362
0
  if (!EXT2FS_IS_64_BITMAP(bmap))
363
0
    return EINVAL;
364
365
0
  INC_STAT(bmap, resize_count);
366
367
0
  return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end);
368
0
}
369
370
errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap,
371
          errcode_t neq,
372
          __u64 end, __u64 *oend)
373
0
{
374
0
  ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
375
376
0
  if (!bitmap)
377
0
    return EINVAL;
378
379
0
  if (EXT2FS_IS_32_BITMAP(bitmap)) {
380
0
    ext2_ino_t tmp_oend;
381
0
    int retval;
382
383
0
    retval = ext2fs_fudge_generic_bitmap_end(gen_bitmap,
384
0
               bitmap->magic,
385
0
               neq, end, &tmp_oend);
386
0
    if (oend)
387
0
      *oend = tmp_oend;
388
0
    return retval;
389
0
  }
390
391
0
  if (!EXT2FS_IS_64_BITMAP(bitmap))
392
0
    return EINVAL;
393
394
0
  if (end > bitmap->real_end)
395
0
    return neq;
396
0
  if (oend)
397
0
    *oend = bitmap->end;
398
0
  bitmap->end = end;
399
0
  return 0;
400
0
}
401
402
__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap gen_bitmap)
403
0
{
404
0
  ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
405
406
0
  if (!bitmap)
407
0
    return EINVAL;
408
409
0
  if (EXT2FS_IS_32_BITMAP(bitmap))
410
0
    return ext2fs_get_generic_bitmap_start(gen_bitmap);
411
412
0
  if (!EXT2FS_IS_64_BITMAP(bitmap))
413
0
    return EINVAL;
414
415
0
  return bitmap->start;
416
0
}
417
418
__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap)
419
0
{
420
0
  ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
421
422
0
  if (!bitmap)
423
0
    return EINVAL;
424
425
0
  if (EXT2FS_IS_32_BITMAP(bitmap))
426
0
    return ext2fs_get_generic_bitmap_end(gen_bitmap);
427
428
0
  if (!EXT2FS_IS_64_BITMAP(bitmap))
429
0
    return EINVAL;
430
431
0
  return bitmap->end;
432
0
}
433
434
void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap gen_bitmap)
435
0
{
436
0
  ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
437
438
0
  if (EXT2FS_IS_32_BITMAP(bitmap))
439
0
    ext2fs_clear_generic_bitmap(gen_bitmap);
440
0
  else
441
0
    bitmap->bitmap_ops->clear_bmap(bitmap);
442
0
}
443
444
int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
445
           __u64 arg)
446
176k
{
447
176k
  ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
448
449
176k
  if (!bitmap)
450
0
    return 0;
451
452
176k
  if (EXT2FS_IS_32_BITMAP(bitmap)) {
453
176k
    if (arg & ~0xffffffffULL) {
454
0
      ext2fs_warn_bitmap2(gen_bitmap,
455
0
              EXT2FS_MARK_ERROR, 0xffffffff);
456
0
      return 0;
457
0
    }
458
176k
    return ext2fs_mark_generic_bitmap(gen_bitmap, arg);
459
176k
  }
460
461
0
  if (!EXT2FS_IS_64_BITMAP(bitmap))
462
0
    return 0;
463
464
0
  arg >>= bitmap->cluster_bits;
465
466
#ifdef ENABLE_BMAP_STATS_OPS
467
  if (arg == bitmap->stats.last_marked + 1)
468
    bitmap->stats.mark_seq++;
469
  if (arg < bitmap->stats.last_marked)
470
    bitmap->stats.mark_back++;
471
  bitmap->stats.last_marked = arg;
472
  bitmap->stats.mark_count++;
473
#endif
474
475
0
  if ((arg < bitmap->start) || (arg > bitmap->end)) {
476
0
    warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg);
477
0
    return 0;
478
0
  }
479
480
0
  return bitmap->bitmap_ops->mark_bmap(bitmap, arg);
481
0
}
482
483
int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
484
             __u64 arg)
485
0
{
486
0
  ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
487
488
0
  if (!bitmap)
489
0
    return 0;
490
491
0
  if (EXT2FS_IS_32_BITMAP(bitmap)) {
492
0
    if (arg & ~0xffffffffULL) {
493
0
      ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_UNMARK_ERROR,
494
0
              0xffffffff);
495
0
      return 0;
496
0
    }
497
0
    return ext2fs_unmark_generic_bitmap(gen_bitmap, arg);
498
0
  }
499
500
0
  if (!EXT2FS_IS_64_BITMAP(bitmap))
501
0
    return 0;
502
503
0
  arg >>= bitmap->cluster_bits;
504
505
0
  INC_STAT(bitmap, unmark_count);
506
507
0
  if ((arg < bitmap->start) || (arg > bitmap->end)) {
508
0
    warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg);
509
0
    return 0;
510
0
  }
511
512
0
  return bitmap->bitmap_ops->unmark_bmap(bitmap, arg);
513
0
}
514
515
int ext2fs_test_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
516
           __u64 arg)
517
0
{
518
0
  ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
519
0
  if (!bitmap)
520
0
    return 0;
521
522
0
  if (EXT2FS_IS_32_BITMAP(bitmap)) {
523
0
    if (arg & ~0xffffffffULL) {
524
0
      ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR,
525
0
              0xffffffff);
526
0
      return 0;
527
0
    }
528
0
    return ext2fs_test_generic_bitmap(gen_bitmap, arg);
529
0
  }
530
531
0
  if (!EXT2FS_IS_64_BITMAP(bitmap))
532
0
    return 0;
533
534
0
  arg >>= bitmap->cluster_bits;
535
536
#ifdef ENABLE_BMAP_STATS_OPS
537
  bitmap->stats.test_count++;
538
  if (arg == bitmap->stats.last_tested + 1)
539
    bitmap->stats.test_seq++;
540
  if (arg < bitmap->stats.last_tested)
541
    bitmap->stats.test_back++;
542
  bitmap->stats.last_tested = arg;
543
#endif
544
545
0
  if ((arg < bitmap->start) || (arg > bitmap->end)) {
546
0
    warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg);
547
0
    return 0;
548
0
  }
549
550
0
  return bitmap->bitmap_ops->test_bmap(bitmap, arg);
551
0
}
552
553
errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
554
          __u64 start, unsigned int num,
555
          void *in)
556
451k
{
557
451k
  ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
558
559
451k
  if (!bmap)
560
0
    return EINVAL;
561
562
451k
  if (EXT2FS_IS_32_BITMAP(bmap)) {
563
451k
    if ((start+num-1) & ~0xffffffffULL) {
564
2
      ext2fs_warn_bitmap2(gen_bmap, EXT2FS_UNMARK_ERROR,
565
2
              0xffffffff);
566
2
      return EINVAL;
567
2
    }
568
451k
    return ext2fs_set_generic_bitmap_range(gen_bmap, bmap->magic,
569
451k
                   start, num, in);
570
451k
  }
571
572
0
  if (!EXT2FS_IS_64_BITMAP(bmap))
573
0
    return EINVAL;
574
575
0
  INC_STAT(bmap, set_range_count);
576
577
0
  return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in);
578
0
}
579
580
errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
581
          __u64 start, unsigned int num,
582
          void *out)
583
78.8k
{
584
78.8k
  ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
585
586
78.8k
  if (!bmap)
587
0
    return EINVAL;
588
589
78.8k
  if (EXT2FS_IS_32_BITMAP(bmap)) {
590
78.8k
    if ((start+num-1) & ~0xffffffffULL) {
591
0
      ext2fs_warn_bitmap2(gen_bmap,
592
0
              EXT2FS_UNMARK_ERROR, 0xffffffff);
593
0
      return EINVAL;
594
0
    }
595
78.8k
    return ext2fs_get_generic_bitmap_range(gen_bmap, bmap->magic,
596
78.8k
                   start, num, out);
597
78.8k
  }
598
599
0
  if (!EXT2FS_IS_64_BITMAP(bmap))
600
0
    return EINVAL;
601
602
0
  INC_STAT(bmap, get_range_count);
603
604
0
  return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out);
605
0
}
606
607
errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
608
              ext2fs_generic_bitmap gen_bm1,
609
              ext2fs_generic_bitmap gen_bm2)
610
0
{
611
0
  ext2fs_generic_bitmap_64 bm1 = (ext2fs_generic_bitmap_64) gen_bm1;
612
0
  ext2fs_generic_bitmap_64 bm2 = (ext2fs_generic_bitmap_64) gen_bm2;
613
0
  blk64_t i;
614
615
0
  if (!bm1 || !bm2)
616
0
    return EINVAL;
617
0
  if (bm1->magic != bm2->magic)
618
0
    return EINVAL;
619
620
  /* Now we know both bitmaps have the same magic */
621
0
  if (EXT2FS_IS_32_BITMAP(bm1))
622
0
    return ext2fs_compare_generic_bitmap(bm1->magic, neq,
623
0
                 gen_bm1, gen_bm2);
624
625
0
  if (!EXT2FS_IS_64_BITMAP(bm1))
626
0
    return EINVAL;
627
628
0
  if ((bm1->start != bm2->start) ||
629
0
      (bm1->end != bm2->end))
630
0
    return neq;
631
632
0
  for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
633
0
    if (ext2fs_test_generic_bmap(gen_bm1, i) !=
634
0
        ext2fs_test_generic_bmap(gen_bm2, i))
635
0
      return neq;
636
637
0
  return 0;
638
0
}
639
640
void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap gen_bmap)
641
0
{
642
0
  ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
643
0
  __u64 start, num;
644
645
0
  if (EXT2FS_IS_32_BITMAP(bmap)) {
646
0
    ext2fs_set_generic_bitmap_padding(gen_bmap);
647
0
    return;
648
0
  }
649
650
0
  start = bmap->end + 1;
651
0
  num = bmap->real_end - bmap->end;
652
0
  bmap->bitmap_ops->mark_bmap_extent(bmap, start, num);
653
  /* XXX ought to warn on error */
654
0
}
655
656
int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
657
            blk64_t block, unsigned int num)
658
0
{
659
0
  ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
660
0
  __u64 end = block + num;
661
662
0
  if (!bmap)
663
0
    return EINVAL;
664
665
0
  if (num == 1)
666
0
    return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap)
667
0
             bmap, block);
668
669
0
  if (EXT2FS_IS_32_BITMAP(bmap)) {
670
0
    if ((block & ~0xffffffffULL) ||
671
0
        ((block+num-1) & ~0xffffffffULL)) {
672
0
      ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
673
0
              EXT2FS_UNMARK_ERROR, 0xffffffff);
674
0
      return EINVAL;
675
0
    }
676
0
    return ext2fs_test_block_bitmap_range(
677
0
      (ext2fs_generic_bitmap) bmap, block, num);
678
0
  }
679
680
0
  if (!EXT2FS_IS_64_BITMAP(bmap))
681
0
    return EINVAL;
682
683
0
  INC_STAT(bmap, test_ext_count);
684
685
  /* convert to clusters if necessary */
686
0
  block >>= bmap->cluster_bits;
687
0
  end += (1ULL << bmap->cluster_bits) - 1;
688
0
  end >>= bmap->cluster_bits;
689
0
  num = end - block;
690
691
0
  if ((block < bmap->start) || (block > bmap->end) ||
692
0
      (block+num-1 > bmap->end)) {
693
0
    ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, block,
694
0
           bmap->description);
695
0
    return EINVAL;
696
0
  }
697
698
0
  return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
699
0
}
700
701
void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
702
             blk64_t block, unsigned int num)
703
421k
{
704
421k
  ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
705
421k
  __u64 end = block + num;
706
707
421k
  if (!bmap)
708
0
    return;
709
710
421k
  if (EXT2FS_IS_32_BITMAP(bmap)) {
711
421k
    if ((block & ~0xffffffffULL) ||
712
421k
        ((block+num-1) & ~0xffffffffULL)) {
713
43.7k
      ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
714
43.7k
              EXT2FS_UNMARK_ERROR, 0xffffffff);
715
43.7k
      return;
716
43.7k
    }
717
377k
    ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
718
377k
                 block, num);
719
377k
  }
720
721
377k
  if (!EXT2FS_IS_64_BITMAP(bmap))
722
377k
    return;
723
724
0
  INC_STAT(bmap, mark_ext_count);
725
726
  /* convert to clusters if necessary */
727
0
  block >>= bmap->cluster_bits;
728
0
  end += (1ULL << bmap->cluster_bits) - 1;
729
0
  end >>= bmap->cluster_bits;
730
0
  num = end - block;
731
732
0
  if ((block < bmap->start) || (block > bmap->end) ||
733
0
      (block+num-1 > bmap->end)) {
734
0
    ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
735
0
           bmap->description);
736
0
    return;
737
0
  }
738
739
0
  bmap->bitmap_ops->mark_bmap_extent(bmap, block, num);
740
0
}
741
742
void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
743
               blk64_t block, unsigned int num)
744
0
{
745
0
  ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
746
0
  __u64 end = block + num;
747
748
0
  if (!bmap)
749
0
    return;
750
751
0
  if (EXT2FS_IS_32_BITMAP(bmap)) {
752
0
    if ((block & ~0xffffffffULL) ||
753
0
        ((block+num-1) & ~0xffffffffULL)) {
754
0
      ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
755
0
              EXT2FS_UNMARK_ERROR, 0xffffffff);
756
0
      return;
757
0
    }
758
0
    ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
759
0
             block, num);
760
0
  }
761
762
0
  if (!EXT2FS_IS_64_BITMAP(bmap))
763
0
    return;
764
765
0
  INC_STAT(bmap, unmark_ext_count);
766
767
  /* convert to clusters if necessary */
768
0
  block >>= bmap->cluster_bits;
769
0
  end += (1ULL << bmap->cluster_bits) - 1;
770
0
  end >>= bmap->cluster_bits;
771
0
  num = end - block;
772
773
0
  if ((block < bmap->start) || (block > bmap->end) ||
774
0
      (block+num-1 > bmap->end)) {
775
0
    ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
776
0
           bmap->description);
777
0
    return;
778
0
  }
779
780
0
  bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num);
781
0
}
782
783
void ext2fs_warn_bitmap32(ext2fs_generic_bitmap gen_bitmap, const char *func)
784
0
{
785
0
  ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
786
787
0
#ifndef OMIT_COM_ERR
788
0
  if (bitmap && bitmap->description)
789
0
    com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
790
0
      "called %s with 64-bit bitmap for %s", func,
791
0
      bitmap->description);
792
0
  else
793
0
    com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
794
0
      "called %s with 64-bit bitmap", func);
795
0
#endif
796
0
}
797
798
errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs,
799
             ext2fs_block_bitmap *bitmap)
800
0
{
801
0
  ext2fs_generic_bitmap_64 bmap, cmap;
802
0
  ext2fs_block_bitmap gen_bmap = *bitmap, gen_cmap;
803
0
  errcode_t   retval;
804
0
  blk64_t     i, next, b_end, c_end;
805
806
0
  bmap = (ext2fs_generic_bitmap_64) gen_bmap;
807
0
  if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(gen_bmap))
808
0
    return 0; /* Nothing to do */
809
810
0
  retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap",
811
0
                &gen_cmap);
812
0
  if (retval)
813
0
    return retval;
814
815
0
  cmap = (ext2fs_generic_bitmap_64) gen_cmap;
816
0
  i = bmap->start;
817
0
  b_end = bmap->end;
818
0
  bmap->end = bmap->real_end;
819
0
  c_end = cmap->end;
820
0
  cmap->end = cmap->real_end;
821
0
  while (i < bmap->real_end) {
822
0
    retval = ext2fs_find_first_set_block_bitmap2(gen_bmap,
823
0
            i, bmap->real_end, &next);
824
0
    if (retval)
825
0
      break;
826
0
    ext2fs_mark_block_bitmap2(gen_cmap, next);
827
0
    i = EXT2FS_C2B(fs, EXT2FS_B2C(fs, next) + 1);
828
0
  }
829
0
  bmap->end = b_end;
830
0
  cmap->end = c_end;
831
0
  ext2fs_free_block_bitmap(gen_bmap);
832
0
  *bitmap = (ext2fs_block_bitmap) cmap;
833
0
  return 0;
834
0
}
835
836
errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap,
837
                __u64 start, __u64 end, __u64 *out)
838
0
{
839
0
  ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
840
0
  __u64 cstart, cend, cout;
841
0
  errcode_t retval;
842
843
0
  if (!bitmap)
844
0
    return EINVAL;
845
846
0
  if (EXT2FS_IS_32_BITMAP(bitmap)) {
847
0
    blk_t blk = 0;
848
849
0
    if (((start) & ~0xffffffffULL) ||
850
0
        ((end) & ~0xffffffffULL)) {
851
0
      ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
852
0
      return EINVAL;
853
0
    }
854
855
0
    retval = ext2fs_find_first_zero_generic_bitmap(bitmap, start,
856
0
                     end, &blk);
857
0
    if (retval == 0)
858
0
      *out = blk;
859
0
    return retval;
860
0
  }
861
862
0
  if (!EXT2FS_IS_64_BITMAP(bitmap))
863
0
    return EINVAL;
864
865
0
  cstart = start >> bmap64->cluster_bits;
866
0
  cend = end >> bmap64->cluster_bits;
867
868
0
  if (cstart < bmap64->start || cend > bmap64->end || start > end) {
869
0
    warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
870
0
    return EINVAL;
871
0
  }
872
873
0
  if (bmap64->bitmap_ops->find_first_zero) {
874
0
    retval = bmap64->bitmap_ops->find_first_zero(bmap64, cstart,
875
0
                   cend, &cout);
876
0
    if (retval)
877
0
      return retval;
878
0
  found:
879
0
    cout <<= bmap64->cluster_bits;
880
0
    *out = (cout >= start) ? cout : start;
881
0
    return 0;
882
0
  }
883
884
0
  for (cout = cstart; cout <= cend; cout++)
885
0
    if (!bmap64->bitmap_ops->test_bmap(bmap64, cout))
886
0
      goto found;
887
888
0
  return ENOENT;
889
0
}
890
891
errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap,
892
               __u64 start, __u64 end, __u64 *out)
893
0
{
894
0
  ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
895
0
  __u64 cstart, cend, cout;
896
0
  errcode_t retval;
897
898
0
  if (!bitmap)
899
0
    return EINVAL;
900
901
0
  if (EXT2FS_IS_32_BITMAP(bitmap)) {
902
0
    blk_t blk = 0;
903
904
0
    if (((start) & ~0xffffffffULL) ||
905
0
        ((end) & ~0xffffffffULL)) {
906
0
      ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
907
0
      return EINVAL;
908
0
    }
909
910
0
    retval = ext2fs_find_first_set_generic_bitmap(bitmap, start,
911
0
                    end, &blk);
912
0
    if (retval == 0)
913
0
      *out = blk;
914
0
    return retval;
915
0
  }
916
917
0
  if (!EXT2FS_IS_64_BITMAP(bitmap))
918
0
    return EINVAL;
919
920
0
  cstart = start >> bmap64->cluster_bits;
921
0
  cend = end >> bmap64->cluster_bits;
922
923
0
  if (cstart < bmap64->start || cend > bmap64->end || start > end) {
924
0
    warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
925
0
    return EINVAL;
926
0
  }
927
928
0
  if (bmap64->bitmap_ops->find_first_set) {
929
0
    retval = bmap64->bitmap_ops->find_first_set(bmap64, cstart,
930
0
                  cend, &cout);
931
0
    if (retval)
932
0
      return retval;
933
0
  found:
934
0
    cout <<= bmap64->cluster_bits;
935
0
    *out = (cout >= start) ? cout : start;
936
0
    return 0;
937
0
  }
938
939
0
  for (cout = cstart; cout <= cend; cout++)
940
0
    if (bmap64->bitmap_ops->test_bmap(bmap64, cout))
941
0
      goto found;
942
943
0
  return ENOENT;
944
0
}
945
946
errcode_t ext2fs_count_used_clusters(ext2_filsys fs, blk64_t start,
947
             blk64_t end, blk64_t *out)
948
0
{
949
0
  blk64_t   next;
950
0
  blk64_t   tot_set = 0;
951
0
  errcode_t retval = 0;
952
953
0
  while (start < end) {
954
0
    retval = ext2fs_find_first_set_block_bitmap2(fs->block_map,
955
0
              start, end, &next);
956
0
    if (retval) {
957
0
      if (retval == ENOENT)
958
0
        retval = 0;
959
0
      break;
960
0
    }
961
0
    start = next;
962
963
0
    retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
964
0
              start, end, &next);
965
0
    if (retval == 0) {
966
0
      tot_set += next - start;
967
0
      start  = next + 1;
968
0
    } else if (retval == ENOENT) {
969
0
      retval = 0;
970
0
      tot_set += end - start + 1;
971
0
      break;
972
0
    } else
973
0
      break;
974
0
  }
975
976
0
  if (!retval)
977
0
    *out = EXT2FS_NUM_B2C(fs, tot_set);
978
0
  return retval;
979
0
}