Coverage Report

Created: 2025-06-22 06:56

/src/lvm2/libdm/datastruct/bitset.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
3
 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
4
 *
5
 * This file is part of the device-mapper userspace tools.
6
 *
7
 * This copyrighted material is made available to anyone wishing to use,
8
 * modify, copy, or redistribute it subject to the terms and conditions
9
 * of the GNU Lesser General Public License v.2.1.
10
 *
11
 * You should have received a copy of the GNU Lesser General Public License
12
 * along with this program; if not, write to the Free Software Foundation,
13
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14
 */
15
16
#include "libdm/misc/dmlib.h"
17
18
#include <ctype.h>
19
20
/* FIXME: calculate this. */
21
0
#define INT_SHIFT 5
22
23
dm_bitset_t dm_bitset_create(struct dm_pool *mem, unsigned num_bits)
24
0
{
25
0
  unsigned n = (num_bits / DM_BITS_PER_INT) + 2;
26
0
  size_t size = sizeof(int) * n;
27
0
  dm_bitset_t bs;
28
  
29
0
  if (mem)
30
0
    bs = dm_pool_zalloc(mem, size);
31
0
  else
32
0
    bs = dm_zalloc(size);
33
34
0
  if (!bs)
35
0
    return NULL;
36
37
0
  *bs = num_bits;
38
39
0
  return bs;
40
0
}
41
42
void dm_bitset_destroy(dm_bitset_t bs)
43
0
{
44
0
  dm_free(bs);
45
0
}
46
47
int dm_bitset_equal(dm_bitset_t in1, dm_bitset_t in2)
48
0
{
49
0
  int i;
50
51
0
  for (i = (in1[0] / DM_BITS_PER_INT) + 1; i; i--)
52
0
    if (in1[i] != in2[i])
53
0
      return 0;
54
55
0
  return 1;
56
0
}
57
58
void dm_bit_and(dm_bitset_t out, dm_bitset_t in1, dm_bitset_t in2)
59
0
{
60
0
  int i;
61
62
0
  for (i = (in1[0] / DM_BITS_PER_INT) + 1; i; i--)
63
0
    out[i] = in1[i] & in2[i];
64
0
}
65
void dm_bit_union(dm_bitset_t out, dm_bitset_t in1, dm_bitset_t in2)
66
0
{
67
0
  int i;
68
0
  for (i = (in1[0] / DM_BITS_PER_INT) + 1; i; i--)
69
0
    out[i] = in1[i] | in2[i];
70
0
}
71
72
static int _test_word(uint32_t test, int bit)
73
0
{
74
0
  uint32_t tb = test >> bit;
75
76
0
  return (tb ? ffs(tb) + bit - 1 : -1);
77
0
}
78
79
static int _test_word_rev(uint32_t test, int bit)
80
0
{
81
0
  uint32_t tb = test << (DM_BITS_PER_INT - 1 - bit);
82
83
0
  return (tb ? bit - clz(tb) : -1);
84
0
}
85
86
int dm_bit_get_next(dm_bitset_t bs, int last_bit)
87
0
{
88
0
  int bit, word;
89
0
  uint32_t test;
90
91
0
  last_bit++;   /* otherwise we'll return the same bit again */
92
93
  /*
94
   * bs[0] holds number of bits
95
   */
96
0
  while (last_bit < (int) bs[0]) {
97
0
    word = last_bit >> INT_SHIFT;
98
0
    test = bs[word + 1];
99
0
    bit = last_bit & (DM_BITS_PER_INT - 1);
100
101
0
    if ((bit = _test_word(test, bit)) >= 0)
102
0
      return (word * DM_BITS_PER_INT) + bit;
103
104
0
    last_bit = last_bit - (last_bit & (DM_BITS_PER_INT - 1)) +
105
0
        DM_BITS_PER_INT;
106
0
  }
107
108
0
  return -1;
109
0
}
110
111
int dm_bit_get_prev(dm_bitset_t bs, int last_bit)
112
0
{
113
0
  int bit, word;
114
0
  uint32_t test;
115
116
0
  last_bit--;   /* otherwise we'll return the same bit again */
117
118
  /*
119
   * bs[0] holds number of bits
120
   */
121
0
  while (last_bit >= 0) {
122
0
    word = last_bit >> INT_SHIFT;
123
0
    test = bs[word + 1];
124
0
    bit = last_bit & (DM_BITS_PER_INT - 1);
125
126
0
    if ((bit = _test_word_rev(test, bit)) >= 0)
127
0
      return (word * DM_BITS_PER_INT) + bit;
128
129
0
    last_bit = (last_bit & ~(DM_BITS_PER_INT - 1)) - 1;
130
0
  }
131
132
0
  return -1;
133
0
}
134
135
int dm_bit_get_first(dm_bitset_t bs)
136
0
{
137
0
  return dm_bit_get_next(bs, -1);
138
0
}
139
140
int dm_bit_get_last(dm_bitset_t bs)
141
0
{
142
0
  return dm_bit_get_prev(bs, bs[0] + 1);
143
0
}
144
145
/*
146
 * Based on the Linux kernel __bitmap_parselist from lib/bitmap.c
147
 */
148
DM_EXPORT_NEW_SYMBOL(dm_bitset_t, dm_bitset_parse_list, 1_02_138)
149
  (const char *str, struct dm_pool *mem, size_t min_num_bits)
150
0
{
151
0
  unsigned a, b;
152
0
  int c, old_c, totaldigits, ndigits;
153
0
  size_t nmaskbits;
154
0
  int at_start, in_range;
155
0
  dm_bitset_t mask = NULL;
156
0
  const char *start = str;
157
0
  size_t len;
158
159
0
scan:
160
0
  len = strlen(str);
161
0
  totaldigits = c = 0;
162
0
  nmaskbits = 0;
163
0
  do {
164
0
    at_start = 1;
165
0
    in_range = 0;
166
0
    a = b = 0;
167
0
    ndigits = totaldigits;
168
169
    /* Get the next value or range of values */
170
0
    while (len) {
171
0
      old_c = c;
172
0
      c = *str++;
173
0
      len--;
174
0
      if (isspace(c))
175
0
        continue;
176
177
      /* A '\0' or a ',' signal the end of a value or range */
178
0
      if (c == '\0' || c == ',')
179
0
        break;
180
      /*
181
      * whitespaces between digits are not allowed,
182
      * but it's ok if whitespaces are on head or tail.
183
      * when old_c is whitespace,
184
      * if totaldigits == ndigits, whitespace is on head.
185
      * if whitespace is on tail, it should not run here.
186
      * as c was ',' or '\0',
187
      * the last code line has broken the current loop.
188
      */
189
0
      if ((totaldigits != ndigits) && isspace(old_c))
190
0
        goto_bad;
191
192
0
      if (c == '-') {
193
0
        if (at_start || in_range)
194
0
          goto_bad;
195
0
        b = 0;
196
0
        in_range = 1;
197
0
        at_start = 1;
198
0
        continue;
199
0
      }
200
201
0
      if (!isdigit(c))
202
0
        goto_bad;
203
204
0
      b = b * 10 + (c - '0');
205
0
      if (!in_range)
206
0
        a = b;
207
0
      at_start = 0;
208
0
      totaldigits++;
209
0
    }
210
0
    if (ndigits == totaldigits)
211
0
      continue;
212
    /* if no digit is after '-', it's wrong */
213
0
    if (at_start && in_range)
214
0
      goto_bad;
215
0
    if (!(a <= b))
216
0
      goto_bad;
217
0
    if (b >= nmaskbits)
218
0
      nmaskbits = b + 1;
219
0
    while ((a <= b) && mask) {
220
0
      dm_bit_set(mask, a);
221
0
      a++;
222
0
    }
223
0
  } while (len && c == ',');
224
225
0
  if (!mask) {
226
0
    if (min_num_bits && (nmaskbits < min_num_bits))
227
0
      nmaskbits = min_num_bits;
228
229
0
    if (!(mask = dm_bitset_create(mem, nmaskbits)))
230
0
      goto_bad;
231
0
    str = start;
232
0
    goto scan;
233
0
  }
234
235
0
  return mask;
236
0
bad:
237
0
  if (mask) {
238
0
    if (mem)
239
0
      dm_pool_free(mem, mask);
240
0
    else
241
0
      dm_bitset_destroy(mask);
242
0
  }
243
0
  return NULL;
244
0
}
245
246
#if defined(GNU_SYMVER)
247
/*
248
 * Maintain backward compatibility with older versions that did not
249
 * accept a 'min_num_bits' argument to dm_bitset_parse_list().
250
 */
251
DM_EXPORT_SYMBOL(dm_bitset_parse_list, 1_02_129)
252
dm_bitset_t dm_bitset_parse_list_v1_02_129(const char *str, struct dm_pool *mem);
253
dm_bitset_t dm_bitset_parse_list_v1_02_129(const char *str, struct dm_pool *mem)
254
0
{
255
0
  return dm_bitset_parse_list(str, mem, 0);
256
0
}
257
258
#endif