Files

95 lines
2.3 KiB
Go
Raw Permalink Normal View History

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: MIT
package nfs4
import (
"slices"
"sourcedock.dev/petrbalvin/nfs/internal/xdr"
)
// maxBitmapWords is the word count limit of a bitmap4. The protocol caps
// the array at 100 words; the attribute table today ends far below that.
const maxBitmapWords = 100
// A Bitmap is a bitmap4: a compact set of attribute numbers.
type Bitmap []uint32
// OfBits returns a Bitmap carrying exactly the given attribute numbers.
func OfBits(bits ...uint32) Bitmap {
if len(bits) == 0 {
return Bitmap{}
}
var words Bitmap
for _, n := range bits {
w := int(n / 32)
for len(words) <= w {
words = append(words, 0)
}
words[w] |= 1 << (n % 32)
}
return words
}
// Has reports whether the attribute number n is set.
func (m Bitmap) Has(n uint32) bool {
w := int(n / 32)
return w < len(m) && m[w]&(1<<(n%32)) != 0
}
// With returns a bitmap carrying n in addition to what was already set.
// Words the original bitmap already held are never dropped, even when the
// new bit lands in a lower word.
func (m Bitmap) With(n uint32) Bitmap {
w := int(n / 32)
out := make(Bitmap, max(w+1, len(m)))
copy(out, m)
out[w] |= 1 << (n % 32)
return out
}
// AppendTo appends the bitmap in wire form: a count of words followed by
// the words, with trailing zero words trimmed.
func (m Bitmap) AppendTo(b []byte) []byte {
trimmed := m
for len(trimmed) > 0 && trimmed[len(trimmed)-1] == 0 {
trimmed = trimmed[:len(trimmed)-1]
}
b = xdr.AppendUint32(b, uint32(len(trimmed)))
for _, w := range trimmed {
b = xdr.AppendUint32(b, w)
}
return b
}
// ReadBitmap reads a bitmap4. A bitmap beyond the word limit is refused
// before any of it is buffered.
func ReadBitmap(d *xdr.Decoder) (Bitmap, error) {
n, err := d.Uint32()
if err != nil {
return nil, err
}
if n > maxBitmapWords {
return nil, xdr.ErrBadLength
}
m := make(Bitmap, 0, n)
for range n {
w, err := d.Uint32()
if err != nil {
return nil, err
}
m = append(m, w)
}
return m, nil
}
// Words reports the words of the bitmap, without trailing zero words.
func (m Bitmap) Words() []uint32 {
trimmed := slices.Clone(m)
for len(trimmed) > 0 && trimmed[len(trimmed)-1] == 0 {
trimmed = trimmed[:len(trimmed)-1]
}
return trimmed
}