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>
353 lines
8.7 KiB
Go
353 lines
8.7 KiB
Go
package rardecode
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/fs"
|
|
"path"
|
|
"slices"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type fileInfo struct {
|
|
h *fileBlockHeader
|
|
}
|
|
|
|
func (f fileInfo) Name() string { return path.Base(f.h.Name) }
|
|
func (f fileInfo) Size() int64 { return f.h.UnPackedSize }
|
|
func (f fileInfo) Mode() fs.FileMode { return f.h.Mode() }
|
|
func (f fileInfo) ModTime() time.Time { return f.h.ModificationTime }
|
|
func (f fileInfo) IsDir() bool { return f.h.IsDir }
|
|
func (f fileInfo) Sys() any { return nil }
|
|
|
|
type dirEntry struct {
|
|
h *fileBlockHeader
|
|
}
|
|
|
|
func (d dirEntry) Name() string { return path.Base(d.h.Name) }
|
|
func (d dirEntry) IsDir() bool { return d.h.IsDir }
|
|
func (d dirEntry) Type() fs.FileMode { return d.h.Mode().Type() }
|
|
func (d dirEntry) Info() (fs.FileInfo, error) { return fileInfo(d), nil }
|
|
|
|
type dummyDirInfo struct {
|
|
name string
|
|
}
|
|
|
|
func (d dummyDirInfo) Name() string { return d.name }
|
|
func (d dummyDirInfo) Size() int64 { return 0 }
|
|
func (d dummyDirInfo) Mode() fs.FileMode { return 0777 | fs.ModeDir }
|
|
func (d dummyDirInfo) ModTime() time.Time { return time.Time{} }
|
|
func (d dummyDirInfo) IsDir() bool { return true }
|
|
func (d dummyDirInfo) Sys() any { return nil }
|
|
|
|
func newDummyDirInfo(name string) dummyDirInfo {
|
|
return dummyDirInfo{name: path.Base(name)}
|
|
}
|
|
|
|
type dummyDirEntry struct {
|
|
name string
|
|
}
|
|
|
|
func (d dummyDirEntry) Name() string { return d.name }
|
|
func (d dummyDirEntry) IsDir() bool { return true }
|
|
func (d dummyDirEntry) Type() fs.FileMode { return fs.ModeDir }
|
|
func (d dummyDirEntry) Sys() any { return nil }
|
|
func (d dummyDirEntry) Info() (fs.FileInfo, error) { return dummyDirInfo(d), nil }
|
|
|
|
func newDummyDirEntry(name string) dummyDirEntry {
|
|
return dummyDirEntry{name: path.Base(name)}
|
|
}
|
|
|
|
type dirFile struct {
|
|
name string
|
|
info fs.FileInfo
|
|
files []fs.DirEntry
|
|
index int
|
|
}
|
|
|
|
func (df *dirFile) Read(p []byte) (int, error) { return 0, io.EOF }
|
|
func (df *dirFile) ReadByte() (byte, error) { return 0, io.EOF }
|
|
func (df *dirFile) Stat() (fs.FileInfo, error) { return df.info, nil }
|
|
func (df *dirFile) Close() error { return nil }
|
|
|
|
func (d *dirFile) ReadDir(n int) ([]fs.DirEntry, error) {
|
|
if n <= 0 {
|
|
return d.files, nil
|
|
}
|
|
l := d.files[d.index:]
|
|
d.index += len(l)
|
|
return l, nil
|
|
}
|
|
|
|
type fsNode struct {
|
|
name string
|
|
blocks *fileBlockList
|
|
files []*fsNode
|
|
}
|
|
|
|
func (n *fsNode) isDir() bool {
|
|
return n.blocks == nil || n.blocks.isDir()
|
|
}
|
|
|
|
func (n *fsNode) hasFileHash() bool {
|
|
return n.blocks != nil && n.blocks.hasFileHash()
|
|
}
|
|
|
|
func (n *fsNode) firstBlock() *fileBlockHeader {
|
|
if n.blocks == nil {
|
|
return nil
|
|
}
|
|
return n.blocks.firstBlock()
|
|
}
|
|
|
|
func (n *fsNode) fileInfo() fs.FileInfo {
|
|
h := n.firstBlock()
|
|
if h == nil {
|
|
return newDummyDirInfo(n.name)
|
|
}
|
|
return fileInfo{h: h}
|
|
}
|
|
|
|
func (n *fsNode) dirEntry() fs.DirEntry {
|
|
h := n.firstBlock()
|
|
if h == nil {
|
|
return newDummyDirEntry(n.name)
|
|
}
|
|
return dirEntry{h: h}
|
|
}
|
|
|
|
func (n *fsNode) dirEntryList() []fs.DirEntry {
|
|
list := make([]fs.DirEntry, len(n.files))
|
|
for i := range list {
|
|
list[i] = n.files[i].dirEntry()
|
|
}
|
|
slices.SortFunc(list, func(a, b fs.DirEntry) int {
|
|
return strings.Compare(a.Name(), b.Name())
|
|
})
|
|
return list
|
|
}
|
|
|
|
// RarFS implements the fs.FS interface for accessing files in a rar archive.
|
|
type RarFS struct {
|
|
vm *volumeManager
|
|
ftree map[string]*fsNode
|
|
}
|
|
|
|
func (rfs *RarFS) openArchiveFile(blocks *fileBlockList) (fs.File, error) {
|
|
return rfs.vm.openArchiveFile(blocks)
|
|
}
|
|
|
|
// Open opens the named file.
|
|
func (rfs *RarFS) Open(name string) (fs.File, error) {
|
|
if !fs.ValidPath(name) {
|
|
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid}
|
|
}
|
|
node := rfs.ftree[name]
|
|
if node == nil {
|
|
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
|
}
|
|
if node.isDir() {
|
|
return &dirFile{
|
|
name: name,
|
|
info: node.fileInfo(),
|
|
files: node.dirEntryList(),
|
|
}, nil
|
|
}
|
|
f, err := rfs.openArchiveFile(node.blocks)
|
|
if err != nil {
|
|
return nil, &fs.PathError{Op: "open", Path: name, Err: err}
|
|
}
|
|
return f, nil
|
|
}
|
|
|
|
// ReadDir reads the named directory and returns a list of directory entries sorted by filename.
|
|
func (rfs *RarFS) ReadDir(name string) ([]fs.DirEntry, error) {
|
|
if !fs.ValidPath(name) {
|
|
return nil, &fs.PathError{Op: "readdir", Path: name, Err: fs.ErrInvalid}
|
|
}
|
|
node := rfs.ftree[name]
|
|
if node == nil {
|
|
return nil, &fs.PathError{Op: "readdir", Path: name, Err: fs.ErrNotExist}
|
|
}
|
|
if !node.isDir() {
|
|
return nil, &fs.PathError{Op: "readdir", Path: name, Err: fs.ErrInvalid}
|
|
}
|
|
return node.dirEntryList(), nil
|
|
}
|
|
|
|
// ReadFile reads the named file from the file system fs and returns its contents.
|
|
func (rfs *RarFS) ReadFile(name string) ([]byte, error) {
|
|
if !fs.ValidPath(name) {
|
|
return nil, &fs.PathError{Op: "readfile", Path: name, Err: fs.ErrInvalid}
|
|
}
|
|
node := rfs.ftree[name]
|
|
if node == nil {
|
|
return nil, &fs.PathError{Op: "readfile", Path: name, Err: fs.ErrNotExist}
|
|
}
|
|
if node.isDir() {
|
|
return []byte{}, nil
|
|
}
|
|
|
|
f, err := rfs.openArchiveFile(node.blocks)
|
|
if err != nil {
|
|
return nil, &fs.PathError{Op: "readfile", Path: name, Err: err}
|
|
}
|
|
defer f.Close()
|
|
|
|
h := node.firstBlock()
|
|
if h.UnKnownSize {
|
|
return io.ReadAll(f)
|
|
}
|
|
buf := make([]byte, h.UnPackedSize)
|
|
_, err = io.ReadFull(f, buf)
|
|
return buf, err
|
|
}
|
|
|
|
/*
|
|
func (rfs *RarFS) Check(name string) error {
|
|
if !fs.ValidPath(name) {
|
|
return &fs.PathError{Op: "check", Path: name, Err: fs.ErrInvalid}
|
|
}
|
|
node := rfs.ftree[name]
|
|
if node == nil {
|
|
return &fs.PathError{Op: "check", Path: name, Err: fs.ErrNotExist}
|
|
}
|
|
if node.isDir() {
|
|
return &fs.PathError{Op: "check", Path: name, Err: fs.ErrInvalid}
|
|
}
|
|
if !node.hasFileHash() {
|
|
return nil
|
|
}
|
|
f, err := rfs.openArchiveFile(node.blocks)
|
|
if err != nil {
|
|
return &fs.PathError{Op: "check", Path: name, Err: err}
|
|
}
|
|
_, err = io.Copy(io.Discard, f)
|
|
if err != nil {
|
|
return &fs.PathError{Op: "check", Path: name, Err: err}
|
|
}
|
|
return nil
|
|
}
|
|
*/
|
|
|
|
// Stat returns a FileInfo describing the named file from the filesystem.
|
|
func (rfs *RarFS) Stat(name string) (fs.FileInfo, error) {
|
|
if !fs.ValidPath(name) {
|
|
return nil, &fs.PathError{Op: "stat", Path: name, Err: fs.ErrInvalid}
|
|
}
|
|
node := rfs.ftree[name]
|
|
if node == nil {
|
|
return nil, &fs.PathError{Op: "stat", Path: name, Err: fs.ErrNotExist}
|
|
}
|
|
return node.fileInfo(), nil
|
|
}
|
|
|
|
// Sub returns an FS corresponding to the subtree rooted at fsys's dir.
|
|
func (rfs *RarFS) Sub(dir string) (fs.FS, error) {
|
|
if dir == "." {
|
|
return rfs, nil
|
|
}
|
|
if !fs.ValidPath(dir) {
|
|
return nil, &fs.PathError{Op: "sub", Path: dir, Err: fs.ErrInvalid}
|
|
}
|
|
node := rfs.ftree[dir]
|
|
if node == nil {
|
|
return nil, &fs.PathError{Op: "sub", Path: dir, Err: fs.ErrNotExist}
|
|
}
|
|
if !node.isDir() {
|
|
return nil, &fs.PathError{Op: "sub", Path: dir, Err: fs.ErrInvalid}
|
|
}
|
|
newFS := &RarFS{
|
|
ftree: map[string]*fsNode{
|
|
".": {name: ".", files: node.files},
|
|
},
|
|
vm: rfs.vm,
|
|
}
|
|
prefix := dir + "/"
|
|
for k, v := range rfs.ftree {
|
|
if strings.HasPrefix(k, prefix) {
|
|
newFS.ftree[strings.TrimPrefix(k, prefix)] = v
|
|
}
|
|
}
|
|
return newFS, nil
|
|
}
|
|
|
|
func listFileBlocks(name string, opts []Option) (*volumeManager, []*fileBlockList, error) {
|
|
options := getOptions(opts)
|
|
if options.openCheck {
|
|
options.skipCheck = false
|
|
}
|
|
v, err := openVolume(name, options)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
pr := newPackedFileReader(v, options)
|
|
defer v.Close()
|
|
|
|
fileBlocks := []*fileBlockList{}
|
|
for {
|
|
blocks, err := pr.nextFile()
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
return v.vm, fileBlocks, nil
|
|
}
|
|
return nil, nil, err
|
|
}
|
|
fileBlocks = append(fileBlocks, blocks)
|
|
if options.openCheck && blocks.hasFileHash() {
|
|
f, err := pr.newArchiveFile(blocks)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
_, err = io.Copy(io.Discard, f)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func OpenFS(name string, opts ...Option) (*RarFS, error) {
|
|
vm, fileBlocks, err := listFileBlocks(name, opts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rfs := &RarFS{
|
|
ftree: map[string]*fsNode{},
|
|
vm: vm,
|
|
}
|
|
for _, blocks := range fileBlocks {
|
|
h := blocks.firstBlock()
|
|
fname := strings.TrimPrefix(path.Clean(h.Name), "/")
|
|
if !fs.ValidPath(fname) {
|
|
return nil, fmt.Errorf("rardecode: archived file has invalid path: %s", fname)
|
|
}
|
|
node := rfs.ftree[fname]
|
|
if node != nil {
|
|
if node.blocks == nil || node.firstBlock().Version < h.Version {
|
|
node.blocks = blocks
|
|
}
|
|
continue
|
|
}
|
|
rfs.ftree[fname] = &fsNode{blocks: blocks}
|
|
prev := rfs.ftree[fname]
|
|
// add parent file nodes
|
|
for fname != "." {
|
|
fname = path.Dir(fname)
|
|
node = rfs.ftree[fname]
|
|
if node != nil {
|
|
node.files = append(node.files, prev)
|
|
break
|
|
}
|
|
rfs.ftree[fname] = &fsNode{
|
|
name: fname,
|
|
files: []*fsNode{prev},
|
|
}
|
|
prev = rfs.ftree[fname]
|
|
}
|
|
}
|
|
return rfs, nil
|
|
}
|