]> Sergey Matveev's repositories - glocate.git/blob - reader.go
Use Go 1.24
[glocate.git] / reader.go
1 // glocate -- ZFS-diff-friendly locate-like utility
2 // Copyright (C) 2022-2025 Sergey Matveev <stargrave@stargrave.org>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, version 3 of the License.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16 package main
17
18 import (
19         "bufio"
20         "encoding/binary"
21         "io"
22         "log"
23         "slices"
24
25         "github.com/klauspost/compress/zstd"
26 )
27
28 func mustReadFull(r io.Reader, buf []byte) {
29         if _, err := io.ReadFull(r, buf); err != nil {
30                 log.Fatalln(err)
31         }
32 }
33
34 func reader(src io.Reader, sink chan Ent) {
35         comp, err := zstd.NewReader(src)
36         if err != nil {
37                 log.Fatalln(err)
38         }
39         br := bufio.NewReaderSize(comp, 1<<17)
40
41         num := make([]byte, 8)
42         var cols []string
43         var namePrev string
44         var nameLen uint16
45         var depth, depthPrev uint8
46         for {
47                 _, err = io.ReadFull(br, num[:2])
48                 if err != nil {
49                         if err == io.EOF {
50                                 break
51                         }
52                         log.Fatalln(err)
53                 }
54                 nameLen = binary.BigEndian.Uint16(num[:2])
55                 nameRaw := make([]byte, nameLen)
56                 mustReadFull(br, nameRaw)
57                 name := string(nameRaw)
58                 mustReadFull(br, num[:1])
59                 depth = uint8(num[0])
60                 mustReadFull(br, num)
61                 ent := Ent{mtime: int64(binary.BigEndian.Uint64(num))}
62                 mustReadFull(br, num)
63                 ent.size = int64(binary.BigEndian.Uint64(num))
64                 if depth > depthPrev {
65                         cols = append(cols, namePrev[:len(namePrev)-1])
66                 } else if depth < depthPrev {
67                         cols = cols[:len(cols)-int(depthPrev-depth)]
68                 }
69                 ent.name = slices.Clone(append(cols, name))
70                 sink <- ent
71                 namePrev = name
72                 depthPrev = depth
73         }
74         close(sink)
75         comp.Close()
76 }