95 lines
2.3 KiB
Go
95 lines
2.3 KiB
Go
package firefly
|
|
|
|
import (
|
|
"firefly-launcher/pkg/firefly/pb"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"golang.org/x/exp/mmap"
|
|
)
|
|
|
|
|
|
func LDiffFile(data *pb.AssetManifest, assetName string, assetSize int64, ldiffsDir, outputDir string) error {
|
|
path := filepath.Join(ldiffsDir, data.ChunkFileName)
|
|
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
return fmt.Errorf("%s does not exist: %w", path, err)
|
|
}
|
|
|
|
fileSize := info.Size()
|
|
var buffer []byte
|
|
|
|
if fileSize > 10*1024*1024 && data.HdiffFileSize > 1*1024*1024 {
|
|
// mmap for large files using x/exp/mmap
|
|
reader, err := mmap.Open(path)
|
|
if err != nil {
|
|
// fallback to buffered read
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return fmt.Errorf("error opening file %s: %w", path, err)
|
|
}
|
|
defer file.Close()
|
|
buffer, err = ReadBuffer(file, data.HdiffFileInChunkOffset, data.HdiffFileSize)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
defer reader.Close()
|
|
buffer = make([]byte, data.HdiffFileSize)
|
|
_, err := reader.ReadAt(buffer, data.HdiffFileInChunkOffset)
|
|
if err != nil {
|
|
return fmt.Errorf("error reading mmap data: %w", err)
|
|
}
|
|
}
|
|
} else {
|
|
// small files, buffered read
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return fmt.Errorf("error opening file %s: %w", path, err)
|
|
}
|
|
defer file.Close()
|
|
|
|
buffer, err = ReadBuffer(file, data.HdiffFileInChunkOffset, data.HdiffFileSize)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
extension := ""
|
|
if data.OriginalFileSize != 0 || assetSize != data.HdiffFileSize {
|
|
extension = ".hdiff"
|
|
}
|
|
assetPath := filepath.Join(outputDir, assetName+extension)
|
|
parentDir := filepath.Dir(assetPath)
|
|
if _, err := os.Stat(parentDir); os.IsNotExist(err) {
|
|
if err := os.MkdirAll(parentDir, 0o755); err != nil {
|
|
return fmt.Errorf("error creating directory %s: %w", parentDir, err)
|
|
}
|
|
}
|
|
|
|
if err := os.WriteFile(assetPath, buffer, 0o644); err != nil {
|
|
return fmt.Errorf("error writing file %s: %w", assetPath, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
|
|
|
|
func ReadBuffer(file *os.File, offset int64, size int64) ([]byte, error) {
|
|
buffer := make([]byte, size)
|
|
|
|
n, err := file.ReadAt(buffer, offset)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error reading data: %w", err)
|
|
}
|
|
if int64(n) != size {
|
|
return nil, fmt.Errorf("expected %d bytes, but read %d bytes", size, n)
|
|
}
|
|
|
|
return buffer, nil
|
|
}
|
|
|