package main import ( "errors" "os" "path/filepath" "strings" ) func sqlitePathChanged(current, next RecorderSettings) bool { return normalizeDatabaseType(current.DatabaseType) == databaseTypeSQLite && normalizeDatabaseType(next.DatabaseType) == databaseTypeSQLite && normalizeSQLitePath(current.SQLitePath) != normalizeSQLitePath(next.SQLitePath) } func moveSQLiteDatabaseForSettings(current, next RecorderSettings) error { currentConfig, err := buildModelStoreConfigFromRecorderSettings(current) if err != nil { return err } nextConfig, err := buildModelStoreConfigFromRecorderSettings(next) if err != nil { return err } return moveSQLiteDatabaseFiles(currentConfig.SQLitePath, nextConfig.SQLitePath) } func restoreModelStoreForSettings(rec RecorderSettings) { config, err := buildModelStoreConfigFromRecorderSettings(rec) if err != nil { return } store := NewModelStore(config) if err := store.Load(); err != nil { _ = store.Close() return } setModelStore(store) } func moveSQLiteDatabaseFiles(sourcePath, targetPath string) error { sourcePath = filepath.Clean(strings.TrimSpace(sourcePath)) targetPath = filepath.Clean(strings.TrimSpace(targetPath)) if sourcePath == "" || targetPath == "" { return errors.New("sqlite source/target path fehlt") } if sourcePath == targetPath { return nil } sourceInfo, err := os.Stat(sourcePath) if errors.Is(err, os.ErrNotExist) { return nil } if err != nil { return err } if sourceInfo.IsDir() { return appErrorf("sqlite source path ist ein ordner: %s", sourcePath) } if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil { return err } for _, target := range append([]string{targetPath}, sqliteSidecarPaths(targetPath)...) { if _, err := os.Stat(target); err == nil { return appErrorf("Ziel-Datei existiert bereits: %s", target) } else if err != nil && !errors.Is(err, os.ErrNotExist) { return err } } if store := getModelStore(); store != nil && store.isSQLite() && store.db != nil { _, _ = store.db.Exec(`PRAGMA wal_checkpoint(TRUNCATE);`) _ = store.Close() } if err := moveDatabaseFile(sourcePath, targetPath); err != nil { return err } sourceSidecars := sqliteSidecarPaths(sourcePath) targetSidecars := sqliteSidecarPaths(targetPath) for i, source := range sourceSidecars { if _, err := os.Stat(source); errors.Is(err, os.ErrNotExist) { continue } else if err != nil { return err } if err := moveDatabaseFile(source, targetSidecars[i]); err != nil { return err } } return nil } func sqliteSidecarPaths(path string) []string { return []string{ path + "-wal", path + "-shm", path + "-journal", } } func moveDatabaseFile(sourcePath, targetPath string) error { if err := renameWithRetry(sourcePath, targetPath); err == nil { return nil } if _, err := copyDatabaseFile(sourcePath, targetPath); err != nil { return err } return removeWithRetry(sourcePath) }