168 lines
3.9 KiB
Go
168 lines
3.9 KiB
Go
package data
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/flate"
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
)
|
|
|
|
type File struct {
|
|
Size int64 `json:"size"`
|
|
ZSize int64 `json:"zsize"`
|
|
Offset int64 `json:"offset"`
|
|
}
|
|
|
|
func (f *File) Read(pf *os.File, b []byte) (int, error) {
|
|
if f.ZSize > 0 {
|
|
compressed := make([]byte, f.ZSize)
|
|
_, err := pf.ReadAt(compressed, f.Offset)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
// Decompress
|
|
reader := flate.NewReader(bytes.NewReader(compressed))
|
|
defer reader.Close()
|
|
n, err := reader.Read(b)
|
|
if err != nil && err != io.EOF {
|
|
fmt.Println("Error reading file:", err, n, compressed)
|
|
return 0, err
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
return pf.ReadAt(b, f.Offset)
|
|
}
|
|
|
|
type FileSystem struct {
|
|
Files map[string]File `json:"files"`
|
|
fp *os.File
|
|
}
|
|
|
|
func (fs *FileSystem) ToJSON() (string, error) {
|
|
data, err := json.Marshal(fs)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to marshal FileSystem to JSON: %v", err)
|
|
}
|
|
return string(data), nil
|
|
}
|
|
|
|
func FromJSON(jsonStr string) (*FileSystem, error) {
|
|
var fs FileSystem
|
|
err := json.Unmarshal([]byte(jsonStr), &fs)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal JSON to FileSystem: %v", err)
|
|
}
|
|
return &fs, nil
|
|
}
|
|
|
|
func (fs *FileSystem) AddFile(name string, size int64, offset int64) {
|
|
if fs.Files == nil {
|
|
fs.Files = make(map[string]File)
|
|
}
|
|
fs.Files[name] = File{Size: size, Offset: offset}
|
|
}
|
|
|
|
func (fs *FileSystem) GetFile(name string) (File, bool) {
|
|
file, exists := fs.Files[name]
|
|
return file, exists
|
|
}
|
|
|
|
func (fs *FileSystem) ListFiles() []string {
|
|
keys := make([]string, 0, len(fs.Files))
|
|
for k := range fs.Files {
|
|
keys = append(keys, k)
|
|
}
|
|
return keys
|
|
}
|
|
|
|
func (fs *FileSystem) ReadFile(name string) ([]byte, int, error) {
|
|
err := fs.openContainerFile()
|
|
if err != nil {
|
|
return []byte{}, 0, fmt.Errorf("failed to open container file: %v", err)
|
|
}
|
|
file, exists := fs.GetFile(name)
|
|
if !exists {
|
|
return []byte{}, 0, fmt.Errorf("file %s not found", name)
|
|
}
|
|
|
|
b := make([]byte, file.Size)
|
|
len, err := file.Read(fs.fp, b)
|
|
return b, len, err
|
|
}
|
|
func (fs *FileSystem) openContainerFile() error {
|
|
if fs.fp != nil {
|
|
return nil
|
|
}
|
|
exePath, err := os.Executable()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get executable path: %v", err)
|
|
}
|
|
fp, err := os.Open(exePath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open executable file: %v", err)
|
|
}
|
|
fs.fp = fp
|
|
return nil
|
|
}
|
|
func (fs *FileSystem) Close() error {
|
|
if fs.fp != nil {
|
|
err := fs.fp.Close()
|
|
fs.fp = nil
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetFileSystem() (*FileSystem, error) {
|
|
exePath, err := os.Executable()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get executable path: %v", err)
|
|
}
|
|
fp, err := os.Open(exePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open executable file: %v", err)
|
|
}
|
|
defer fp.Close()
|
|
// Seek to the end to find the JSON metadata
|
|
stat, err := fp.Stat()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to stat executable file: %v", err)
|
|
}
|
|
size := stat.Size()
|
|
if size < 8 {
|
|
return nil, fmt.Errorf("executable file is too small to contain metadata")
|
|
}
|
|
_, err = fp.Seek(-8, io.SeekEnd)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to seek to end of executable file: %v", err)
|
|
}
|
|
var fsSize uint64
|
|
err = binary.Read(fp, binary.LittleEndian, &fsSize)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode metadata size: %v", err)
|
|
}
|
|
fmt.Println("fsSize:", fsSize)
|
|
if fsSize == 0 || fsSize > uint64(size-8) {
|
|
return nil, fmt.Errorf("invalid metadata size: %d", fsSize)
|
|
}
|
|
_, err = fp.Seek(-(8 + int64(fsSize)), io.SeekEnd)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to seek to metadata position: %v", err)
|
|
}
|
|
jsonData := make([]byte, fsSize)
|
|
_, err = fp.Read(jsonData)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read metadata: %v", err)
|
|
}
|
|
var fs FileSystem
|
|
err = json.Unmarshal(jsonData, &fs)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode JSON metadata: %v", err)
|
|
}
|
|
return &fs, nil
|
|
}
|