241 lines
5.2 KiB
Go
241 lines
5.2 KiB
Go
package file
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
|
|
"apigo.cc/go/encoding"
|
|
"apigo.cc/go/safe"
|
|
)
|
|
|
|
type MemFile struct {
|
|
Name string
|
|
AbsName string
|
|
ModTime time.Time
|
|
IsDir bool
|
|
Compressed bool
|
|
Size int64
|
|
Data []byte
|
|
SafeData *safe.SafeBuf
|
|
}
|
|
|
|
type MemFileB64 struct {
|
|
Name string
|
|
ModTime time.Time
|
|
IsDir bool
|
|
DataB64 []byte
|
|
Compressed bool
|
|
Size int64
|
|
Children []MemFileB64
|
|
}
|
|
|
|
var (
|
|
memFiles = make(map[string]*MemFile)
|
|
memFilesByDir = make(map[string][]MemFile)
|
|
memFilesLock sync.RWMutex
|
|
)
|
|
|
|
func (mf *MemFile) GetData() []byte {
|
|
if mf.Compressed && len(mf.Data) > 0 {
|
|
return MustGunzip(mf.Data)
|
|
}
|
|
return mf.Data
|
|
}
|
|
|
|
func (mf *MemFile) GetSafeData() *safe.SecretPlaintext {
|
|
if mf.SafeData != nil {
|
|
return mf.SafeData.Open()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetAbsFilename(filename string) string {
|
|
if !filepath.IsAbs(filename) {
|
|
if absName, err := filepath.Abs(filename); err == nil {
|
|
filename = absName
|
|
}
|
|
}
|
|
return filename
|
|
}
|
|
|
|
func AddFileToMemory(mf MemFile) {
|
|
mf.Name = GetAbsFilename(mf.Name)
|
|
mf.AbsName = mf.Name
|
|
dirName := filepath.Dir(mf.Name)
|
|
memFilesLock.Lock()
|
|
defer memFilesLock.Unlock()
|
|
memFiles[mf.Name] = &mf
|
|
if dirName != "" && dirName != "." {
|
|
memFilesByDir[dirName] = append(memFilesByDir[dirName], mf)
|
|
}
|
|
}
|
|
|
|
func ReadFileFromMemory(name string) *MemFile {
|
|
name = GetAbsFilename(name)
|
|
memFilesLock.RLock()
|
|
defer memFilesLock.RUnlock()
|
|
return memFiles[name]
|
|
}
|
|
|
|
func ReadDirFromMemory(name string) []MemFile {
|
|
name = GetAbsFilename(name)
|
|
memFilesLock.RLock()
|
|
defer memFilesLock.RUnlock()
|
|
mfList := memFilesByDir[name]
|
|
if mfList == nil {
|
|
return nil
|
|
}
|
|
out := make([]MemFile, len(mfList))
|
|
copy(out, mfList)
|
|
return out
|
|
}
|
|
|
|
func LoadFileToMemory(filename string) {
|
|
loadFileToMemory(filename, false, false)
|
|
}
|
|
|
|
func SafeLoadFileToMemory(filename string) {
|
|
loadFileToMemory(filename, false, true)
|
|
}
|
|
|
|
func LoadFileToMemoryWithCompress(filename string) {
|
|
loadFileToMemory(filename, true, false)
|
|
}
|
|
|
|
func SafeLoadFileToMemoryWithCompress(filename string) {
|
|
loadFileToMemory(filename, true, true)
|
|
}
|
|
|
|
func loadFileToMemory(filename string, compress bool, isSafe bool) {
|
|
if info, err := os.Stat(filename); err == nil {
|
|
if info.IsDir() {
|
|
AddFileToMemory(MemFile{
|
|
Name: filename,
|
|
ModTime: info.ModTime(),
|
|
IsDir: true,
|
|
Size: info.Size(),
|
|
})
|
|
if files, err := os.ReadDir(filename); err == nil {
|
|
for _, file := range files {
|
|
loadFileToMemory(filepath.Join(filename, file.Name()), compress, isSafe)
|
|
}
|
|
}
|
|
} else {
|
|
if data, err := os.ReadFile(filename); err == nil {
|
|
compressed := false
|
|
var dataBuf *safe.SafeBuf
|
|
if compress {
|
|
if data2, err := Compress(data, "gzip"); err == nil {
|
|
if isSafe {
|
|
safe.ZeroMemory(data)
|
|
}
|
|
data = data2
|
|
compressed = true
|
|
}
|
|
}
|
|
if isSafe {
|
|
dataBuf = safe.NewSafeBuf(data)
|
|
safe.ZeroMemory(data)
|
|
data = nil
|
|
}
|
|
AddFileToMemory(MemFile{
|
|
Name: filename,
|
|
ModTime: info.ModTime(),
|
|
IsDir: false,
|
|
Size: info.Size(),
|
|
Data: data,
|
|
SafeData: dataBuf,
|
|
Compressed: compressed,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func LoadFileToB64(filename string) *MemFileB64 {
|
|
if info, err := os.Stat(filename); err == nil {
|
|
if info.IsDir() {
|
|
out := MemFileB64{
|
|
Name: filename,
|
|
ModTime: info.ModTime(),
|
|
IsDir: true,
|
|
Size: info.Size(),
|
|
Children: make([]MemFileB64, 0),
|
|
}
|
|
if files, err := os.ReadDir(filename); err == nil {
|
|
for _, file := range files {
|
|
if mfB64 := LoadFileToB64(filepath.Join(filename, file.Name())); mfB64 != nil {
|
|
out.Children = append(out.Children, *mfB64)
|
|
}
|
|
}
|
|
}
|
|
return &out
|
|
} else {
|
|
if data, err := os.ReadFile(filename); err == nil {
|
|
compressed := false
|
|
if buf, err := Compress(data, "gzip"); err == nil {
|
|
data = buf
|
|
compressed = true
|
|
}
|
|
return &MemFileB64{
|
|
Name: filename,
|
|
ModTime: info.ModTime(),
|
|
IsDir: false,
|
|
Size: info.Size(),
|
|
DataB64: encoding.Base64(data),
|
|
Compressed: compressed,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func LoadFilesToMemoryFromB64(b64File *MemFileB64) {
|
|
if data, err := encoding.UnBase64(b64File.DataB64); err == nil {
|
|
if b64File.Compressed {
|
|
data = MustGunzip(data)
|
|
}
|
|
memFile := MemFile{
|
|
Name: b64File.Name,
|
|
ModTime: b64File.ModTime,
|
|
IsDir: b64File.IsDir,
|
|
Size: b64File.Size,
|
|
Data: data,
|
|
}
|
|
AddFileToMemory(memFile)
|
|
if memFile.IsDir && len(b64File.Children) > 0 {
|
|
for _, child := range b64File.Children {
|
|
LoadFilesToMemoryFromB64(&child)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func LoadFilesToMemoryFromB64KeepGzip(b64File *MemFileB64) {
|
|
if data, err := encoding.UnBase64(b64File.DataB64); err == nil {
|
|
memFile := MemFile{
|
|
Name: b64File.Name,
|
|
ModTime: b64File.ModTime,
|
|
IsDir: b64File.IsDir,
|
|
Size: b64File.Size,
|
|
Data: data,
|
|
}
|
|
AddFileToMemory(memFile)
|
|
if memFile.IsDir && len(b64File.Children) > 0 {
|
|
for _, child := range b64File.Children {
|
|
LoadFilesToMemoryFromB64KeepGzip(&child)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func LoadFilesToMemoryFromJson(jsonFiles string) {
|
|
dirData := MemFileB64{}
|
|
_ = json.Unmarshal([]byte(jsonFiles), &dirData)
|
|
LoadFilesToMemoryFromB64(&dirData)
|
|
}
|