Tighten disk safety checks

This commit is contained in:
2026-04-24 07:18:17 +03:00
parent b8eabee393
commit 75c6b928ae
5 changed files with 92 additions and 8 deletions

View File

@@ -5,12 +5,17 @@ import (
"errors"
"os"
"path/filepath"
"strings"
"jukebox_maker/internal/disk"
)
type OverwriteMode string
type FileSelectMode string
const (
DefaultDestFolder = "media"
OverwriteSkip OverwriteMode = "skip"
OverwriteDelete OverwriteMode = "delete"
@@ -30,12 +35,14 @@ type Config struct {
OverwriteMode OverwriteMode `json:"overwrite_mode"`
FileSelectMode FileSelectMode `json:"file_select_mode"`
AutoCopy bool `json:"auto_copy"`
FileReplicaCounts map[string]int `json:"file_replica_counts,omitempty"`
DiskReplicaFiles map[string][]string `json:"disk_replica_files,omitempty"`
}
func defaults() Config {
return Config{
ReserveFreeGB: 2.0,
DestFolder: "media",
DestFolder: DefaultDestFolder,
OverwriteMode: OverwriteSkip,
FileSelectMode: SelectNew,
AutoCopy: false,
@@ -55,6 +62,11 @@ func Load(path string) (*Config, error) {
if err := json.Unmarshal(data, &cfg); err != nil {
return nil, err
}
if destFolder, err := NormalizeDestFolder(cfg.DestFolder); err == nil {
cfg.DestFolder = destFolder
} else {
cfg.DestFolder = defaults().DestFolder
}
return &cfg, nil
}
@@ -77,6 +89,9 @@ func (c *Config) Validate() error {
if c.ReserveFreeGB < 0 {
return errors.New("reserve_free_gb must be >= 0")
}
if _, err := NormalizeDestFolder(c.DestFolder); err != nil {
return err
}
switch c.OverwriteMode {
case OverwriteSkip, OverwriteDelete:
default:
@@ -89,3 +104,26 @@ func (c *Config) Validate() error {
}
return nil
}
func NormalizeDestFolder(value string) (string, error) {
value = strings.TrimSpace(value)
if value == "" {
return DefaultDestFolder, nil
}
clean := filepath.ToSlash(filepath.Clean(value))
clean = strings.TrimPrefix(clean, "./")
clean = strings.TrimPrefix(clean, "/")
switch clean {
case "", ".", "..":
return "", errors.New("dest_folder must be a subfolder on disk, not the disk root")
}
if strings.HasPrefix(clean, "../") {
return "", errors.New("dest_folder must stay inside the disk")
}
if clean == disk.MarkerDir || strings.HasPrefix(clean, disk.MarkerDir+"/") {
return "", errors.New("dest_folder conflicts with internal disk metadata")
}
return clean, nil
}