package persistence import ( "errors" "fmt" "os" ) type Config struct { BlobRoot string MasterkeyFile string } type Persistence struct { blobRoot string masterkey []byte } func New(config Config) (*Persistence, error) { if config.MasterkeyFile == "" { return nil, errors.New("no masterkey file specified") } blobRoot := "./data/blobs" if config.BlobRoot != "" { blobRoot = config.BlobRoot } if err := ensureBlobsDir(blobRoot); err != nil { return nil, err } // the master key used to derive encryption keys masterkey, err := os.ReadFile(config.MasterkeyFile) if err != nil { return nil, fmt.Errorf("cannot read postern masterkey: %w", err) } return &Persistence{ blobRoot: blobRoot, masterkey: masterkey, }, nil } func (p *Persistence) BlobRoot() string { return p.blobRoot } func ensureBlobsDir(path string) error { if err := os.MkdirAll(path, 0700); err != nil { return fmt.Errorf("creating blobs directory %s: %w", path, err) } return nil } // CheckDirWritable ensures that the persistence layer can write to the given directory func CheckDirWritable(dir string) error { if dir == "" { return errors.New("no path given") } info, err := os.Stat(dir) if err != nil { if os.IsNotExist(err) { return fmt.Errorf("directory does not exist: %s", dir) } return fmt.Errorf("failed to stat directory: %w", err) } // Ensure it's a directory if !info.IsDir() { return fmt.Errorf("path is not a directory: %s", dir) } // Test writability by creating a temporary file writeTest, err := os.CreateTemp(dir, ".write_test") if err != nil { return fmt.Errorf("directory is not writable: %w", err) } _ = writeTest.Close() // Clean up the test file err = os.Remove(writeTest.Name()) if err != nil { return fmt.Errorf("directory is writable but not deletable: %w", err) } return nil }