sbctl/util.go

129 lines
2.8 KiB
Go

package sbctl
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"errors"
"io"
"os"
"path/filepath"
"strings"
)
func ChecksumFile(file string) (string, error) {
hasher := sha256.New()
s, err := os.ReadFile(file)
if err != nil {
return "", err
}
hasher.Write(s)
return hex.EncodeToString(hasher.Sum(nil)), nil
}
func CreateDirectory(path string) error {
if _, err := os.Stat(path); errors.Is(err, os.ErrExist) {
return nil
} else if errors.Is(err, os.ErrNotExist) {
} else if err != nil {
return err
}
if err := os.MkdirAll(path, os.ModePerm); err != nil {
return err
}
return nil
}
func ReadOrCreateFile(filePath string) ([]byte, error) {
// Try to access or create the file itself
f, err := os.ReadFile(filePath)
if err != nil {
// Errors will mainly happen due to permissions or non-existing file
if os.IsNotExist(err) {
// First, guarantee the directory's existence
// os.MkdirAll simply returns nil if the directory already exists
fileDir := filepath.Dir(filePath)
if err = os.MkdirAll(fileDir, os.ModePerm); err != nil {
return nil, err
}
file, err := os.Create(filePath)
if err != nil {
return nil, err
}
file.Close()
// Create zero-length f, which is equivalent to what would be read from empty file
f = make([]byte, 0)
} else {
if os.IsPermission(err) {
return nil, err
}
return nil, err
}
}
return f, nil
}
var EfivarFSFiles = []string{
"/sys/firmware/efi/efivars/PK-8be4df61-93ca-11d2-aa0d-00e098032b8c",
"/sys/firmware/efi/efivars/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c",
"/sys/firmware/efi/efivars/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f",
}
var ErrImmutable = errors.New("file is immutable")
var ErrNotImmutable = errors.New("file is not immutable")
func IsImmutable(file string) error {
f, err := os.Open(file)
// Files in efivarfs might not exist. Ignore them
if errors.Is(err, os.ErrNotExist) {
return nil
} else if err != nil {
return err
}
attr, err := GetAttr(f)
if err != nil {
return err
}
if (attr & FS_IMMUTABLE_FL) != 0 {
return ErrImmutable
}
return ErrNotImmutable
}
func CheckMSDos(path string) (bool, error) {
r, err := os.Open(path)
if err != nil {
return false, err
}
defer r.Close()
// We are looking for MS-DOS executables.
// They contain "MZ" as the two first bytes
var header [2]byte
if _, err = io.ReadFull(r, header[:]); err != nil {
return false, err
}
if !bytes.Equal(header[:], []byte{0x4d, 0x5a}) {
return false, nil
}
return true, nil
}
var (
checked = make(map[string]bool)
)
func AddChecked(path string) {
normalized := strings.Join(strings.Split(path, "/")[2:], "/")
checked[normalized] = true
}
func InChecked(path string) bool {
normalized := strings.Join(strings.Split(path, "/")[2:], "/")
return checked[normalized]
}