mirror of
https://github.com/go-gitea/gitea.git
synced 2026-04-19 05:50:54 +00:00
fix
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
@@ -172,50 +173,46 @@ headerLoop:
|
||||
return id, DiscardFull(rd, size-n+1)
|
||||
}
|
||||
|
||||
// git tree files are a list:
|
||||
// <mode-in-ascii> SP <fname> NUL <binary Hash>
|
||||
//
|
||||
// Unfortunately this 20-byte notation is somewhat in conflict to all other git tools
|
||||
// Therefore we need some method to convert these binary hashes to hex hashes
|
||||
|
||||
// ParseCatFileTreeLine reads an entry from a tree in a cat-file --batch stream
|
||||
//
|
||||
// Each line is composed of:
|
||||
// <mode-in-ascii-dropping-initial-zeros> SP <fname> NUL <binary HASH>
|
||||
//
|
||||
// We don't attempt to convert the raw HASH to save a lot of time
|
||||
func ParseCatFileTreeLine(objectFormat ObjectFormat, rd BufferedReader) (mode, fname, sha []byte, n int, err error) {
|
||||
// Read the mode and fname up to and including the NUL separator.
|
||||
// ReadBytes (unlike ReadSlice) always returns a freshly allocated slice,
|
||||
// so mode and fname can safely reference into it across subsequent reads.
|
||||
readBytes, err := rd.ReadBytes('\x00')
|
||||
if err != nil {
|
||||
return mode, fname, sha, n, err
|
||||
}
|
||||
idx := bytes.IndexByte(readBytes, ' ')
|
||||
if idx < 0 {
|
||||
log.Debug("missing space in readBytes ParseCatFileTreeLine: %s", readBytes)
|
||||
return mode, fname, sha, n, &ErrNotExist{}
|
||||
}
|
||||
|
||||
mode = readBytes[:idx]
|
||||
fname = readBytes[idx+1 : len(readBytes)-1] // trim the NUL terminator
|
||||
n = len(readBytes)
|
||||
|
||||
// Read the binary hash
|
||||
length := objectFormat.FullLength() / 2
|
||||
sha = make([]byte, length)
|
||||
idx = 0
|
||||
for idx < length {
|
||||
var read int
|
||||
read, err = rd.Read(sha[idx:length])
|
||||
n += read
|
||||
if err != nil {
|
||||
return mode, fname, sha, n, err
|
||||
// Each entry is composed of:
|
||||
// <mode-in-ascii-dropping-initial-zeros> SP <name> NUL <binary-hash>
|
||||
func ParseCatFileTreeLine(objectFormat ObjectFormat, rd BufferedReader) (mode EntryMode, name string, objID ObjectID, n int, err error) {
|
||||
// use the in-buffer memory as much as possible to avoid extra allocations
|
||||
bufBytes, err := rd.ReadSlice('\x00')
|
||||
const maxEntryInfoBytes = 1024 * 1024
|
||||
if errors.Is(err, bufio.ErrBufferFull) {
|
||||
bufBytes = slices.Clone(bufBytes)
|
||||
for len(bufBytes) < maxEntryInfoBytes && errors.Is(err, bufio.ErrBufferFull) {
|
||||
var tmp []byte
|
||||
tmp, err = rd.ReadSlice('\x00')
|
||||
bufBytes = append(bufBytes, tmp...)
|
||||
}
|
||||
idx += read
|
||||
}
|
||||
return mode, fname, sha, n, err
|
||||
if err != nil {
|
||||
return mode, name, objID, len(bufBytes), err
|
||||
}
|
||||
|
||||
idx := bytes.IndexByte(bufBytes, ' ')
|
||||
if idx < 0 {
|
||||
return mode, name, objID, len(bufBytes), errors.New("invalid CatFileTreeLine output")
|
||||
}
|
||||
|
||||
mode = ParseEntryMode(util.UnsafeBytesToString(bufBytes[:idx]))
|
||||
name = string(bufBytes[idx+1 : len(bufBytes)-1]) // trim the NUL terminator
|
||||
if mode == EntryModeNoEntry {
|
||||
return mode, name, objID, len(bufBytes), errors.New("invalid entry mode: " + string(bufBytes[:idx]))
|
||||
}
|
||||
|
||||
switch objectFormat {
|
||||
case Sha1ObjectFormat:
|
||||
objID = &Sha1Hash{}
|
||||
case Sha256ObjectFormat:
|
||||
objID = &Sha256Hash{}
|
||||
default:
|
||||
panic("unsupported object format: " + objectFormat.Name())
|
||||
}
|
||||
readIDLen, err := io.ReadFull(rd, objID.RawValue())
|
||||
return mode, name, objID, len(bufBytes) + readIDLen, err
|
||||
}
|
||||
|
||||
func DiscardFull(rd BufferedReader, discard int64) error {
|
||||
|
||||
@@ -5,10 +5,7 @@ package git
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
// ParseTreeEntries parses the output of a `git ls-tree -l` command.
|
||||
@@ -51,7 +48,7 @@ func catBatchParseTreeEntries(objectFormat ObjectFormat, ptree *Tree, rd Buffere
|
||||
|
||||
loop:
|
||||
for sz > 0 {
|
||||
mode, fname, sha, count, err := ParseCatFileTreeLine(objectFormat, rd)
|
||||
mode, fname, objID, count, err := ParseCatFileTreeLine(objectFormat, rd)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break loop
|
||||
@@ -61,15 +58,9 @@ loop:
|
||||
sz -= int64(count)
|
||||
entry := new(TreeEntry)
|
||||
entry.ptree = ptree
|
||||
|
||||
entry.entryMode = ParseEntryMode(string(mode))
|
||||
if entry.entryMode == EntryModeNoEntry {
|
||||
log.Debug("Unknown mode: %v", string(mode))
|
||||
return nil, fmt.Errorf("unknown mode: %v", string(mode))
|
||||
}
|
||||
|
||||
entry.ID = objectFormat.MustID(sha)
|
||||
entry.name = string(fname)
|
||||
entry.entryMode = mode
|
||||
entry.ID = objID
|
||||
entry.name = fname
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
if _, err := rd.Discard(1); err != nil {
|
||||
|
||||
@@ -8,7 +8,6 @@ package pipeline
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -89,23 +88,23 @@ func findLFSFileFunc(repo *git.Repository, objectID git.ObjectID, revListReader
|
||||
case "tree":
|
||||
var n int64
|
||||
for n < info.Size {
|
||||
mode, fname, binObjectID, count, err := git.ParseCatFileTreeLine(objectID.Type(), batchReader)
|
||||
mode, fname, shaID, count, err := git.ParseCatFileTreeLine(objectID.Type(), batchReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n += int64(count)
|
||||
if bytes.Equal(binObjectID, objectID.RawValue()) {
|
||||
if bytes.Equal(shaID.RawValue(), objectID.RawValue()) {
|
||||
result := LFSResult{
|
||||
Name: curPath + string(fname),
|
||||
Name: curPath + fname,
|
||||
SHA: curCommit.ID.String(),
|
||||
Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0],
|
||||
When: curCommit.Author.When,
|
||||
ParentHashes: curCommit.Parents,
|
||||
}
|
||||
resultsMap[curCommit.ID.String()+":"+curPath+string(fname)] = &result
|
||||
} else if string(mode) == git.EntryModeTree.String() {
|
||||
trees = append(trees, hex.EncodeToString(binObjectID))
|
||||
paths = append(paths, curPath+string(fname)+"/")
|
||||
resultsMap[curCommit.ID.String()+":"+curPath+fname] = &result
|
||||
} else if mode == git.EntryModeTree {
|
||||
trees = append(trees, shaID.String())
|
||||
paths = append(paths, curPath+fname+"/")
|
||||
}
|
||||
}
|
||||
if _, err := batchReader.Discard(1); err != nil {
|
||||
|
||||
@@ -66,9 +66,10 @@ func ParseEntryMode(mode string) EntryMode {
|
||||
return EntryModeSymlink
|
||||
case "160000":
|
||||
return EntryModeCommit
|
||||
case "040000":
|
||||
case "040000", "40000": // leading-zero is optional
|
||||
return EntryModeTree
|
||||
default:
|
||||
// if the faster path didn't work, try parsing the mode as an integer and masking off the file type bits
|
||||
// git uses 040000 for tree object, but some users may get 040755 from non-standard git implementations
|
||||
m, _ := strconv.ParseInt(mode, 8, 32)
|
||||
modeInt := EntryMode(m)
|
||||
|
||||
Reference in New Issue
Block a user