58 lines
1.4 KiB
Go
58 lines
1.4 KiB
Go
package testusers
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"image/png"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// CopyAvatars validates all sources and destination collisions before copying.
|
|
// Existing identical assets are reused. Existing different files are not replaced.
|
|
func CopyAvatars(sourceDir, mediaDir string) error {
|
|
if sourceDir == "" || mediaDir == "" {
|
|
return fmt.Errorf("both avatar source and media directories are required")
|
|
}
|
|
assets := make(map[string][]byte)
|
|
for _, name := range Avatars() {
|
|
data, err := os.ReadFile(filepath.Join(sourceDir, name))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cfg, err := png.DecodeConfig(bytes.NewReader(data))
|
|
if err != nil || cfg.Width < 256 || cfg.Height < 256 {
|
|
return fmt.Errorf("invalid or undersized PNG avatar: %s", name)
|
|
}
|
|
existing, err := os.ReadFile(filepath.Join(mediaDir, name))
|
|
if err == nil {
|
|
if !bytes.Equal(existing, data) {
|
|
return fmt.Errorf("refusing to overwrite different existing avatar: %s", name)
|
|
}
|
|
continue
|
|
}
|
|
if !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
assets[name] = data
|
|
}
|
|
if err := os.MkdirAll(mediaDir, 0755); err != nil {
|
|
return err
|
|
}
|
|
for name, data := range assets {
|
|
file, err := os.OpenFile(filepath.Join(mediaDir, name), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, writeErr := file.Write(data)
|
|
closeErr := file.Close()
|
|
if writeErr != nil {
|
|
return writeErr
|
|
}
|
|
if closeErr != nil {
|
|
return closeErr
|
|
}
|
|
}
|
|
return nil
|
|
}
|