Full Mattermost server source with integrated Community Enterprise features. Includes vendor directory for offline/air-gapped builds. Structure: - enterprise-impl/: Enterprise feature implementations - enterprise-community/: Init files that register implementations - enterprise/: Bridge imports (community_imports.go) - vendor/: All dependencies for offline builds Build (online): go build ./cmd/mattermost Build (offline/air-gapped): go build -mod=vendor ./cmd/mattermost 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
260 lines
4.5 KiB
Go
260 lines
4.5 KiB
Go
package rardecode
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"io"
|
|
"io/fs"
|
|
)
|
|
|
|
const (
|
|
maxSfxSize = 0x100000 // maximum number of bytes to read when searching for RAR signature
|
|
sigPrefix = "Rar!\x1A\x07"
|
|
sigPrefixLen = len(sigPrefix)
|
|
|
|
maxEmptyReads = 100
|
|
|
|
minBufSize = 32
|
|
defaultBufSize = 4096
|
|
)
|
|
|
|
var (
|
|
ErrNoSig = errors.New("rardecode: RAR signature not found")
|
|
ErrNegativeRead = errors.New("rardecode: negative read from Reader")
|
|
)
|
|
|
|
type bufVolumeReader struct {
|
|
r io.Reader
|
|
sr io.Seeker
|
|
buf []byte
|
|
i int
|
|
n int
|
|
off int64
|
|
err error
|
|
ver int
|
|
}
|
|
|
|
func (br *bufVolumeReader) readErr() error {
|
|
err := br.err
|
|
br.err = nil
|
|
return err
|
|
}
|
|
|
|
func (br *bufVolumeReader) fill() error {
|
|
if br.err != nil {
|
|
return br.readErr()
|
|
}
|
|
br.i = 0
|
|
for i := 0; i < maxEmptyReads; i++ {
|
|
br.n, br.err = br.r.Read(br.buf)
|
|
if br.n > 0 {
|
|
return nil
|
|
}
|
|
if br.n < 0 {
|
|
return ErrNegativeRead
|
|
}
|
|
if br.err != nil {
|
|
return br.readErr()
|
|
}
|
|
}
|
|
return io.ErrNoProgress
|
|
}
|
|
|
|
func (br *bufVolumeReader) canSeek() bool {
|
|
return br.sr != nil
|
|
}
|
|
|
|
func (br *bufVolumeReader) seek(offset int64) error {
|
|
if br.sr == nil {
|
|
return fs.ErrInvalid
|
|
}
|
|
start := br.off - int64(br.i)
|
|
end := start + int64(br.n)
|
|
if offset >= start && offset <= end {
|
|
diff := offset - br.off
|
|
br.off += diff
|
|
br.i += int(diff)
|
|
return nil
|
|
}
|
|
_, err := br.sr.Seek(offset, io.SeekStart)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
br.i = 0
|
|
br.n = 0
|
|
br.off = offset
|
|
return nil
|
|
}
|
|
|
|
func (br *bufVolumeReader) Read(p []byte) (int, error) {
|
|
if br.i == br.n {
|
|
err := br.fill()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
n := copy(p, br.buf[br.i:br.n])
|
|
br.i += n
|
|
br.off += int64(n)
|
|
return n, nil
|
|
}
|
|
|
|
func (br *bufVolumeReader) ReadByte() (byte, error) {
|
|
if br.i == br.n {
|
|
err := br.fill()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
c := br.buf[br.i]
|
|
br.i++
|
|
br.off++
|
|
return c, nil
|
|
}
|
|
|
|
func (br *bufVolumeReader) Discard(n int64) error {
|
|
buffered := int64(br.n - br.i)
|
|
if buffered >= n {
|
|
br.i += int(n)
|
|
br.off += n
|
|
return nil
|
|
}
|
|
// empty buffer
|
|
n -= buffered
|
|
br.i = 0
|
|
br.n = 0
|
|
br.off += buffered
|
|
// try seek
|
|
if sr, ok := br.r.(io.Seeker); ok {
|
|
_, err := sr.Seek(n, io.SeekCurrent)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
br.off += n
|
|
return nil
|
|
}
|
|
// copy to discard writer
|
|
written, err := io.CopyN(io.Discard, br.r, n)
|
|
br.off += written
|
|
return err
|
|
}
|
|
|
|
func (br *bufVolumeReader) writeToN(w io.Writer, n int64) (int64, error) {
|
|
if n == 0 {
|
|
return 0, nil
|
|
}
|
|
var err error
|
|
todo := n
|
|
startOffset := br.off
|
|
for todo != 0 && err == nil {
|
|
if br.i == br.n {
|
|
err = br.fill()
|
|
if err != nil {
|
|
break
|
|
}
|
|
}
|
|
buf := br.buf[br.i:br.n]
|
|
if todo > 0 && todo < int64(len(buf)) {
|
|
buf = buf[:todo]
|
|
}
|
|
var l int
|
|
l, err = w.Write(buf)
|
|
br.i += l
|
|
br.off += int64(l)
|
|
if todo > 0 {
|
|
todo -= int64(l)
|
|
}
|
|
}
|
|
if todo < 0 && err == io.EOF {
|
|
err = nil
|
|
}
|
|
return br.off - startOffset, nil
|
|
}
|
|
|
|
// findSig searches for the RAR signature and version at the beginning of a file.
|
|
// It searches no more than maxSfxSize bytes from the file start.
|
|
func (br *bufVolumeReader) findSig() (int, error) {
|
|
for br.off <= maxSfxSize {
|
|
if br.i == br.n {
|
|
err := br.fill()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
n := bytes.IndexByte(br.buf[br.i:br.n], sigPrefix[0])
|
|
if n < 0 {
|
|
br.off += int64(n)
|
|
continue
|
|
}
|
|
br.i += n
|
|
br.off += int64(n)
|
|
// ensure enough bytes available in buffer
|
|
buffered := br.n - br.i
|
|
if buffered < sigPrefixLen+2 {
|
|
br.n = copy(br.buf, br.buf[br.i:br.n])
|
|
br.i = 0
|
|
l, err := io.ReadAtLeast(br.r, br.buf[br.n:], sigPrefixLen+2-buffered)
|
|
br.n += l
|
|
if err != nil {
|
|
if errors.Is(err, io.ErrUnexpectedEOF) {
|
|
err = ErrNoSig
|
|
}
|
|
return 0, err
|
|
}
|
|
}
|
|
if !bytes.HasPrefix(br.buf[br.i:br.n], []byte(sigPrefix)) {
|
|
br.i++
|
|
br.off++
|
|
continue
|
|
}
|
|
br.i += sigPrefixLen
|
|
br.off += int64(sigPrefixLen)
|
|
|
|
ver := int(br.buf[br.i])
|
|
if ver == 0 {
|
|
br.i++
|
|
br.off++
|
|
} else if br.buf[br.i+1] == 0 {
|
|
br.i += 2
|
|
br.off += 2
|
|
} else {
|
|
continue
|
|
}
|
|
return ver, nil
|
|
}
|
|
return 0, ErrNoSig
|
|
}
|
|
|
|
func (br *bufVolumeReader) Reset(r io.Reader) error {
|
|
br.r = r
|
|
br.sr, _ = r.(io.Seeker)
|
|
br.i = 0
|
|
br.n = 0
|
|
br.off = 0
|
|
ver, err := br.findSig()
|
|
if err != nil {
|
|
if errors.Is(err, io.EOF) {
|
|
return ErrNoSig
|
|
}
|
|
return err
|
|
}
|
|
br.ver = ver
|
|
return nil
|
|
}
|
|
|
|
func newBufVolumeReader(r io.Reader, size int) (*bufVolumeReader, error) {
|
|
if size == 0 {
|
|
size = defaultBufSize
|
|
} else {
|
|
size = max(minBufSize, size)
|
|
}
|
|
br := &bufVolumeReader{
|
|
buf: make([]byte, size),
|
|
}
|
|
err := br.Reset(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return br, nil
|
|
}
|