]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/bit.c
libxfs: sanitize agcount on load
[thirdparty/xfsprogs-dev.git] / db / bit.c
1 /*
2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "libxfs.h"
20 #include "bit.h"
21
22 #undef setbit /* defined in param.h on Linux */
23
24 static int getbit(char *ptr, int bit);
25 static void setbit(char *ptr, int bit, int val);
26
27 static int
28 getbit(
29 char *ptr,
30 int bit)
31 {
32 int mask;
33 int shift;
34
35 ptr += byteize(bit);
36 bit = bitoffs(bit);
37 shift = 7 - bit;
38 mask = 1 << shift;
39 return (*ptr & mask) >> shift;
40 }
41
42 static void
43 setbit(
44 char *ptr,
45 int bit,
46 int val)
47 {
48 int mask;
49 int shift;
50
51 ptr += byteize(bit);
52 bit = bitoffs(bit);
53 shift = 7 - bit;
54 mask = (1 << shift);
55 if (val) {
56 *ptr |= mask;
57 } else {
58 mask = ~mask;
59 *ptr &= mask;
60 }
61 }
62
63 __int64_t
64 getbitval(
65 void *obj,
66 int bitoff,
67 int nbits,
68 int flags)
69 {
70 int bit;
71 int i;
72 char *p;
73 __int64_t rval;
74 int signext;
75 int z1, z2, z3, z4;
76
77 ASSERT(nbits<=64);
78
79 p = (char *)obj + byteize(bitoff);
80 bit = bitoffs(bitoff);
81 signext = (flags & BVSIGNED) != 0;
82 z4 = ((intptr_t)p & 0xf) == 0 && bit == 0;
83 if (nbits == 64 && z4)
84 return be64_to_cpu(*(__be64 *)p);
85 z3 = ((intptr_t)p & 0x7) == 0 && bit == 0;
86 if (nbits == 32 && z3) {
87 if (signext)
88 return (__s32)be32_to_cpu(*(__be32 *)p);
89 else
90 return (__u32)be32_to_cpu(*(__be32 *)p);
91 }
92 z2 = ((intptr_t)p & 0x3) == 0 && bit == 0;
93 if (nbits == 16 && z2) {
94 if (signext)
95 return (__s16)be16_to_cpu(*(__be16 *)p);
96 else
97 return (__u16)be16_to_cpu(*(__be16 *)p);
98 }
99 z1 = ((intptr_t)p & 0x1) == 0 && bit == 0;
100 if (nbits == 8 && z1) {
101 if (signext)
102 return *(__s8 *)p;
103 else
104 return *(__u8 *)p;
105 }
106
107
108 for (i = 0, rval = 0LL; i < nbits; i++) {
109 if (getbit(p, bit + i)) {
110 /* If the last bit is on and we care about sign
111 * bits and we don't have a full 64 bit
112 * container, turn all bits on between the
113 * sign bit and the most sig bit.
114 */
115
116 /* handle endian swap here */
117 #if __BYTE_ORDER == LITTLE_ENDIAN
118 if (i == 0 && signext && nbits < 64)
119 rval = -1LL << nbits;
120 rval |= 1LL << (nbits - i - 1);
121 #else
122 if ((i == (nbits - 1)) && signext && nbits < 64)
123 rval |= (-1LL << nbits);
124 rval |= 1LL << (nbits - i - 1);
125 #endif
126 }
127 }
128 return rval;
129 }
130
131 /*
132 * The input data can be 8, 16, 32, and 64 sized numeric values
133 * aligned on a byte boundry, or odd sized numbers stored on odd
134 * aligned offset (for example the bmbt fields).
135 *
136 * The input data sent to this routine has been converted to big endian
137 * and has been adjusted in the array so that the first input bit is to
138 * be written in the first bit in the output.
139 *
140 * If the field length and the output buffer are byte aligned, then use
141 * memcpy from the input to the output, but if either entries are not byte
142 * aligned, then loop over the entire bit range reading the input value
143 * and set/clear the matching bit in the output.
144 *
145 * example when ibuf is not multiple of a byte in length:
146 *
147 * ibuf: | BBBBBBBB | bbbxxxxx |
148 * \\\\\\\\--\\\\
149 * obuf+bitoff: | xBBBBBBB | Bbbbxxxx |
150 *
151 */
152 void
153 setbitval(
154 void *obuf, /* start of buffer to write into */
155 int bitoff, /* bit offset into the output buffer */
156 int nbits, /* number of bits to write */
157 void *ibuf) /* source bits */
158 {
159 char *in = ibuf;
160 char *out = obuf;
161 int bit;
162
163 if (bitoff % NBBY || nbits % NBBY) {
164 for (bit = 0; bit < nbits; bit++)
165 setbit(out, bit + bitoff, getbit(in, bit));
166 } else
167 memcpy(out + byteize(bitoff), in, byteize(nbits));
168 }