git-lfs/git/ls_tree_scanner.go
brian m. carlson 247799dc37
fsck: don't detect symlinks as invalid pointers
Git will never try to filter a symlink, since it is not a regular file.
Extract the file mode from git ls-tree and verify that the blob we're
seeing is a regular file, whether executable or not, and not a symlink.
2021-10-20 20:51:41 +00:00

94 lines
1.7 KiB
Go

package git
import (
"bufio"
"bytes"
"io"
"strconv"
"strings"
)
// An entry from ls-tree or rev-list including a blob sha and tree path
type TreeBlob struct {
Oid string
Size int64
Mode int32
Filename string
}
type LsTreeScanner struct {
s *bufio.Scanner
tree *TreeBlob
}
func NewLsTreeScanner(r io.Reader) *LsTreeScanner {
s := bufio.NewScanner(r)
s.Split(scanNullLines)
return &LsTreeScanner{s: s}
}
func (s *LsTreeScanner) TreeBlob() *TreeBlob {
return s.tree
}
func (s *LsTreeScanner) Err() error {
return nil
}
func (s *LsTreeScanner) Scan() bool {
t, hasNext := s.next()
s.tree = t
return hasNext
}
func (s *LsTreeScanner) next() (*TreeBlob, bool) {
hasNext := s.s.Scan()
line := s.s.Text()
parts := strings.SplitN(line, "\t", 2)
if len(parts) < 2 {
return nil, hasNext
}
attrs := strings.SplitN(parts[0], " ", 4)
if len(attrs) < 4 {
return nil, hasNext
}
mode, err := strconv.ParseInt(strings.TrimSpace(attrs[0]), 8, 32)
if err != nil {
return nil, hasNext
}
if attrs[1] != "blob" {
return nil, hasNext
}
sz, err := strconv.ParseInt(strings.TrimSpace(attrs[3]), 10, 64)
if err != nil {
return nil, hasNext
}
oid := attrs[2]
filename := parts[1]
return &TreeBlob{Oid: oid, Size: sz, Mode: int32(mode), Filename: filename}, hasNext
}
func scanNullLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
if i := bytes.IndexByte(data, '\000'); i >= 0 {
// We have a full null-terminated line.
return i + 1, data[0:i], nil
}
// If we're at EOF, we have a final, non-terminated line. Return it.
if atEOF {
return len(data), data, nil
}
// Request more data.
return 0, nil, nil
}