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
124
|
package main
import (
"bufio"
"crypto/sha256"
"fmt"
"io/fs"
"log"
"net/url"
"os"
"path/filepath"
"time"
)
type metadata struct {
size, mtime, mode int64
// sum [sha256.Size]byte
sum []byte
}
type metamap map[string]metadata
func getIndex(root string, mm metamap) (index string, err error) {
filesystem := os.DirFS(root)
err = fs.WalkDir(filesystem, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
info, err := d.Info()
if err != nil {
return err
}
if info.IsDir() {
if d.Name() == ".bb" {
return fs.SkipDir
}
return nil
}
b, err := os.ReadFile(path)
if err != nil {
return err
}
// md := metadata{info.Size(), info.ModTime().Unix(), int64(info.Mode()), sha256.Sum256(b)}
a := sha256.Sum256(b)
md := metadata{info.Size(), info.ModTime().Unix(), int64(info.Mode()), a[:]}
log.Println(path, md, mm[path])
index += fmt.Sprintf("%s %d %d %o %x\n", url.PathEscape(path), md.size, md.mtime, md.mode, md.sum)
return nil
})
return index, err
}
func readIndex(path string) (md metamap, err error) {
f, err := os.Open(path)
if err != nil {
return md, err
}
defer f.Close()
md = metamap{}
scan := bufio.NewScanner(f)
for scan.Scan() {
var p string
var d metadata
n, err := fmt.Sscanf(scan.Text(), "%s %d %d %o %64x", &p, &d.size, &d.mtime, &d.mode, &d.sum)
if err != nil || n != 5 {
return md, err
}
path, err := url.PathUnescape(p)
if err != nil {
return md, err
}
md[path] = d
}
if err := scan.Err(); err != nil {
return md, err
}
return md, nil
}
func initBB(root string) (current, previous string, err error) {
if err = os.MkdirAll(filepath.Join(root, ".bb", "data"), 0o750); err != nil {
return "", "", err
}
prevs, _ := fs.Glob(os.DirFS(root), filepath.Join(".bb", "index-*"))
if len(prevs) > 0 {
previous = prevs[len(prevs)-1]
}
now := time.Now()
y, m, d := now.Date()
h, mn, s := now.Clock()
current = filepath.Join(root, ".bb", fmt.Sprintf("index-%d-%02d%02d-%02d%02d%02d", y, m, d, h, mn, s))
return current, previous, nil
}
func main() {
log.SetFlags(log.Lshortfile)
wd, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
index, oldindex, err := initBB(wd)
if err != nil {
log.Fatal(err)
}
md := metamap{}
if oldindex != "" {
if md, err = readIndex(oldindex); err != nil {
log.Fatal(err)
}
}
data, err := getIndex(wd, md)
if err != nil {
log.Fatal(err)
}
err = os.WriteFile(index, []byte(data), 0o644)
if err != nil {
log.Fatal(err)
}
}
|