package database import ( "errors" "fmt" "github.com/tevino/abool" "github.com/safing/portmaster/base/utils" ) const ( databasesSubDir = "databases" ) var ( initialized = abool.NewBool(false) shuttingDown = abool.NewBool(false) shutdownSignal = make(chan struct{}) rootStructure *utils.DirStructure databasesStructure *utils.DirStructure ) // InitializeWithPath initializes the database at the specified location using a path. func InitializeWithPath(dirPath string) error { return Initialize(utils.NewDirStructure(dirPath, utils.PublicReadPermission)) } // Initialize initializes the database at the specified location using a dir structure. func Initialize(dirStructureRoot *utils.DirStructure) error { if initialized.SetToIf(false, true) { rootStructure = dirStructureRoot // ensure root and databases dirs databasesStructure = rootStructure.ChildDir(databasesSubDir, utils.AdminOnlyPermission) err := databasesStructure.Ensure() if err != nil { return fmt.Errorf("could not create/open database directory (%s): %w", rootStructure.Path, err) } return nil } return errors.New("database already initialized") } // Shutdown shuts down the whole database system. func Shutdown() (err error) { if shuttingDown.SetToIf(false, true) { close(shutdownSignal) } else { return } controllersLock.RLock() defer controllersLock.RUnlock() for _, c := range controllers { err = c.Shutdown() if err != nil { return } } return } // getLocation returns the storage location for the given name and type. func getLocation(name, storageType string) (string, error) { location := databasesStructure.ChildDir(name, utils.AdminOnlyPermission).ChildDir(storageType, utils.AdminOnlyPermission) // check location err := location.Ensure() if err != nil { return "", fmt.Errorf(`failed to create/check database dir "%s": %w`, location.Path, err) } return location.Path, nil }