更新
This commit is contained in:
+57
@@ -0,0 +1,57 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user