mattermost-community-enterp.../vendor/github.com/nwaples/rardecode/v2/fs.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
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>
2025-12-17 23:59:07 +09:00

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
}