2018-02-10 21:19:26 +03:00
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2021-08-24 19:47:09 +03:00
//go:build !gogit
2020-12-17 17:00:47 +03:00
2018-02-10 21:19:26 +03:00
package git
import (
2021-05-10 04:27:03 +03:00
"bufio"
2018-02-10 21:19:26 +03:00
"bytes"
"fmt"
2021-05-10 04:27:03 +03:00
"io"
2018-02-10 21:19:26 +03:00
"strconv"
2021-02-18 00:32:25 +03:00
"strings"
2021-06-25 19:54:08 +03:00
"code.gitea.io/gitea/modules/log"
2018-02-10 21:19:26 +03:00
)
2021-02-18 00:32:25 +03:00
// ParseTreeEntries parses the output of a `git ls-tree -l` command.
2018-02-10 21:19:26 +03:00
func ParseTreeEntries ( data [ ] byte ) ( [ ] * TreeEntry , error ) {
return parseTreeEntries ( data , nil )
}
func parseTreeEntries ( data [ ] byte , ptree * Tree ) ( [ ] * TreeEntry , error ) {
entries := make ( [ ] * TreeEntry , 0 , 10 )
for pos := 0 ; pos < len ( data ) ; {
2021-02-18 00:32:25 +03:00
// expect line to be of the form "<mode> <type> <sha> <space-padded-size>\t<filename>"
2018-02-10 21:19:26 +03:00
entry := new ( TreeEntry )
entry . ptree = ptree
if pos + 6 > len ( data ) {
return nil , fmt . Errorf ( "Invalid ls-tree output: %s" , string ( data ) )
}
switch string ( data [ pos : pos + 6 ] ) {
case "100644" :
2020-12-17 17:00:47 +03:00
entry . entryMode = EntryModeBlob
2018-02-10 21:19:26 +03:00
pos += 12 // skip over "100644 blob "
case "100755" :
2020-12-17 17:00:47 +03:00
entry . entryMode = EntryModeExec
2018-02-10 21:19:26 +03:00
pos += 12 // skip over "100755 blob "
case "120000" :
2020-12-17 17:00:47 +03:00
entry . entryMode = EntryModeSymlink
2018-02-10 21:19:26 +03:00
pos += 12 // skip over "120000 blob "
case "160000" :
2020-12-17 17:00:47 +03:00
entry . entryMode = EntryModeCommit
2018-02-10 21:19:26 +03:00
pos += 14 // skip over "160000 object "
2022-09-18 04:31:20 +03:00
case "040000" , "040755" : // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
2020-12-17 17:00:47 +03:00
entry . entryMode = EntryModeTree
2018-02-10 21:19:26 +03:00
pos += 12 // skip over "040000 tree "
default :
return nil , fmt . Errorf ( "unknown type: %v" , string ( data [ pos : pos + 6 ] ) )
}
if pos + 40 > len ( data ) {
return nil , fmt . Errorf ( "Invalid ls-tree output: %s" , string ( data ) )
}
id , err := NewIDFromString ( string ( data [ pos : pos + 40 ] ) )
if err != nil {
return nil , fmt . Errorf ( "Invalid ls-tree output: %v" , err )
}
entry . ID = id
pos += 41 // skip over sha and trailing space
2021-02-18 00:32:25 +03:00
end := pos + bytes . IndexByte ( data [ pos : ] , '\t' )
if end < pos {
return nil , fmt . Errorf ( "Invalid ls-tree -l output: %s" , string ( data ) )
}
entry . size , _ = strconv . ParseInt ( strings . TrimSpace ( string ( data [ pos : end ] ) ) , 10 , 64 )
entry . sized = true
pos = end + 1
end = pos + bytes . IndexByte ( data [ pos : ] , '\n' )
2018-02-10 21:19:26 +03:00
if end < pos {
return nil , fmt . Errorf ( "Invalid ls-tree output: %s" , string ( data ) )
}
// In case entry name is surrounded by double quotes(it happens only in git-shell).
if data [ pos ] == '"' {
2020-12-17 17:00:47 +03:00
entry . name , err = strconv . Unquote ( string ( data [ pos : end ] ) )
2018-02-10 21:19:26 +03:00
if err != nil {
return nil , fmt . Errorf ( "Invalid ls-tree output: %v" , err )
}
} else {
2020-12-17 17:00:47 +03:00
entry . name = string ( data [ pos : end ] )
2018-02-10 21:19:26 +03:00
}
pos = end + 1
entries = append ( entries , entry )
}
return entries , nil
}
2021-05-10 04:27:03 +03:00
func catBatchParseTreeEntries ( ptree * Tree , rd * bufio . Reader , sz int64 ) ( [ ] * TreeEntry , error ) {
fnameBuf := make ( [ ] byte , 4096 )
modeBuf := make ( [ ] byte , 40 )
shaBuf := make ( [ ] byte , 40 )
entries := make ( [ ] * TreeEntry , 0 , 10 )
loop :
for sz > 0 {
mode , fname , sha , count , err := ParseTreeLine ( rd , modeBuf , fnameBuf , shaBuf )
if err != nil {
if err == io . EOF {
break loop
}
return nil , err
}
sz -= int64 ( count )
entry := new ( TreeEntry )
entry . ptree = ptree
switch string ( mode ) {
case "100644" :
entry . entryMode = EntryModeBlob
case "100755" :
entry . entryMode = EntryModeExec
case "120000" :
entry . entryMode = EntryModeSymlink
case "160000" :
entry . entryMode = EntryModeCommit
2022-09-18 04:31:20 +03:00
case "40000" , "40755" : // git uses 40000 for tree object, but some users may get 40755 for unknown reasons
2021-05-10 04:27:03 +03:00
entry . entryMode = EntryModeTree
default :
2021-06-25 19:54:08 +03:00
log . Debug ( "Unknown mode: %v" , string ( mode ) )
2021-05-10 04:27:03 +03:00
return nil , fmt . Errorf ( "unknown mode: %v" , string ( mode ) )
}
entry . ID = MustID ( sha )
entry . name = string ( fname )
entries = append ( entries , entry )
}
if _ , err := rd . Discard ( 1 ) ; err != nil {
return entries , err
}
return entries , nil
}