kcrypt/pkg/partition_info/partition_info.go
Dimitris Karakasilis bb144f204a
Don't hide there error when it's not about file not existing
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2022-11-23 14:53:02 +02:00

135 lines
3.5 KiB
Go

package partition_info
import (
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/jaypipes/ghw/pkg/block"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
)
const DefaultPartitionInfoFile = "/oem/partition_info.yaml"
// PartitionInfo maps a partition label to a partition UUID.
// It's used in order to be able to ask the kcrypt-challenger for the passphrase
// using the partition label, even when the label is not accessible (e.g. before
// decrypting the partition). The UUID can be used to lookup the partition label
// and make the request.
type PartitionInfo struct {
file string
mapping map[string]string
}
// NewPartitionInfoFromFile reads the given partition info file (if one exists)
// and returns a pointer to a PartitionInfo object.
// If a file doesn't exist, the function will create one and return an "empty"
// PartitionInfo object.
// The boolean return value indicates whether a file existed or not (true means,
// a file existed already).
func NewPartitionInfoFromFile(file string) (*PartitionInfo, bool, error) {
existed, err := createInfoFileIfNotExists(file)
if err != nil {
return nil, existed, err
}
mapping, err := ParsePartitionInfoFile(file)
if err != nil {
return nil, existed, err
}
return &PartitionInfo{
file: file,
mapping: mapping,
}, existed, nil
}
func (pi PartitionInfo) LookupUUIDForLabel(l string) string {
return pi.mapping[l]
}
func (pi PartitionInfo) LookupLabelForUUID(uuid string) string {
for k, v := range pi.mapping {
if v == uuid {
return k
}
}
return ""
}
// UpdatePartitionLabelMapping takes partition information as a string argument
// the the form: `label:name:uuid` (that's what the `kcrypt encrypt` command returns
// on success. This function stores it in the PartitionInfoFile yaml file for
// later use.
func (pi PartitionInfo) UpdateMapping(partitionData string) error {
label, uuid := PartitionDataFromString(partitionData)
pi.mapping[label] = uuid
return pi.save()
}
func (pi PartitionInfo) IsMappingNil() bool {
return pi.mapping == nil
}
func (pi PartitionInfo) save() error {
data, err := yaml.Marshal(&pi.mapping)
if err != nil {
return errors.Wrap(err, "marshalling the new partition info to yaml")
}
err = ioutil.WriteFile(pi.file, data, 0)
if err != nil {
return errors.Wrap(err, "writing back the partition info file")
}
return nil
}
func PartitionToString(p *block.Partition) string {
return fmt.Sprintf("%s:%s:%s", p.Label, p.Name, p.UUID)
}
// Takes a partition info string (as returned by PartitionToString) and return
// the partition label and the UUID
func PartitionDataFromString(partitionStr string) (string, string) {
parts := strings.Split(partitionStr, ":")
return parts[0], parts[2]
}
func ParsePartitionInfoFile(file string) (map[string]string, error) {
var result map[string]string
yamlFile, err := ioutil.ReadFile(file)
if err != nil {
return result, errors.Wrap(err, "reading the partition info file")
}
err = yaml.Unmarshal(yamlFile, &result)
if err != nil {
return result, errors.Wrap(err, "unmarshalling partition info file")
}
if result == nil {
result = map[string]string{}
}
return result, nil
}
// createInfoFileIfNotExists returns true if file already exists or creates the
// the file if it doesn't exist and returns false.
func createInfoFileIfNotExists(fileName string) (bool, error) {
_, err := os.Stat(fileName)
if errors.Is(err, os.ErrNotExist) {
if _, err := os.Create(fileName); err != nil {
return false, err
}
return false, nil
} else if err != nil {
return false, err
}
return true, nil
}