~emersion/drmdb

ref: 1863c385ab10d14368e69b4f91fada6e04e588b7 drmdb/db.go -rw-r--r-- 2.4 KiB View raw
1863c385Simon Ser curl -X POST is unnecessary when using -d 1 year, 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package drmdb

import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"git.sr.ht/~emersion/drmdb/drmtree"
)

const dbDir = "db"

var errStop = fmt.Errorf("drmdb: stop walking")

func generateKey(n *drmtree.Node) (string, error) {
	if n.Driver == nil || n.Device == nil {
		return "", fmt.Errorf("node is missing driver/device")
	}

	ver := &n.Driver.Version

	var b bytes.Buffer
	b.WriteString(n.Driver.Name)
	b.WriteByte(0)
	fmt.Fprintf(&b, "%v.%v.%v-%v", ver.Major, ver.Minor, ver.Patch, ver.Date)
	b.WriteByte(0)
	b.WriteString(n.Driver.Kernel.SysName)
	b.WriteByte(0)
	b.WriteString(n.Driver.Kernel.Release)
	b.WriteByte(0)
	switch dev := n.Device.DeviceData.(type) {
	case *drmtree.DevicePCI:
		b.WriteString("pci")
		b.WriteByte(0)
		fmt.Fprintf(&b, "%04X:%04X", dev.Vendor, dev.Device)
	case *drmtree.DevicePlatform:
		b.WriteString("platform")
		if len(dev.Compatible) == 0 {
			return "", fmt.Errorf("platform device is missing compatibility info")
		}
		for _, compat := range dev.Compatible {
			b.WriteByte(0)
			b.WriteString(compat)
		}
	default:
		return "", fmt.Errorf("device bus type %v not supported", n.Device.BusType)
	}

	sum := sha256.Sum256(b.Bytes())
	return hex.EncodeToString(sum[:])[:12], nil
}

func store(n *drmtree.Node) (string, error) {
	k, err := generateKey(n)
	if err != nil {
		return "", err
	}

	p := filepath.Join(dbDir, k+".json")
	f, err := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
	if err != nil {
		if os.IsExist(err) {
			return "", fmt.Errorf("data has already been submitted")
		}
		return "", err
	}
	defer f.Close()

	if err := json.NewEncoder(f).Encode(n); err != nil {
		return "", err
	}

	return k, f.Close()
}

func load(k string) (*drmtree.Node, error) {
	p := filepath.Join(dbDir, k + ".json")
	f, err := os.Open(p)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var n drmtree.Node
	if err := json.NewDecoder(f).Decode(&n); err != nil {
		return nil, err
	}

	return &n, f.Close()
}

func walk(fn func(k string, n *drmtree.Node) error) error {
	files, err := ioutil.ReadDir(dbDir)
	if err != nil {
		return err
	}

	for _, fi := range files {
		if !strings.HasSuffix(fi.Name(), ".json") {
			continue
		}
		k := strings.TrimSuffix(fi.Name(), ".json")

		n, err := load(k)
		if err != nil {
			return err
		}

		if err := fn(k, n); err == errStop {
			return nil
		} else if err != nil {
			return err
		}
	}

	return nil
}