Skip to content

Commit d9497ba

Browse files
authored
Merge pull request go-git#967 from niukuo/filename
plumbing: object, check legitimacy in (*Tree).Encode
2 parents efdd399 + 1d4bec0 commit d9497ba

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

plumbing/object/tree.go

+32
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io"
88
"path"
99
"path/filepath"
10+
"sort"
1011
"strings"
1112

1213
"github.com/go-git/go-git/v5/plumbing"
@@ -27,6 +28,7 @@ var (
2728
ErrFileNotFound = errors.New("file not found")
2829
ErrDirectoryNotFound = errors.New("directory not found")
2930
ErrEntryNotFound = errors.New("entry not found")
31+
ErrEntriesNotSorted = errors.New("entries in tree are not sorted")
3032
)
3133

3234
// Tree is basically like a directory - it references a bunch of other trees
@@ -270,6 +272,28 @@ func (t *Tree) Decode(o plumbing.EncodedObject) (err error) {
270272
return nil
271273
}
272274

275+
type TreeEntrySorter []TreeEntry
276+
277+
func (s TreeEntrySorter) Len() int {
278+
return len(s)
279+
}
280+
281+
func (s TreeEntrySorter) Less(i, j int) bool {
282+
name1 := s[i].Name
283+
name2 := s[j].Name
284+
if s[i].Mode == filemode.Dir {
285+
name1 += "/"
286+
}
287+
if s[j].Mode == filemode.Dir {
288+
name2 += "/"
289+
}
290+
return name1 < name2
291+
}
292+
293+
func (s TreeEntrySorter) Swap(i, j int) {
294+
s[i], s[j] = s[j], s[i]
295+
}
296+
273297
// Encode transforms a Tree into a plumbing.EncodedObject.
274298
func (t *Tree) Encode(o plumbing.EncodedObject) (err error) {
275299
o.SetType(plumbing.TreeObject)
@@ -279,7 +303,15 @@ func (t *Tree) Encode(o plumbing.EncodedObject) (err error) {
279303
}
280304

281305
defer ioutil.CheckClose(w, &err)
306+
307+
if !sort.IsSorted(TreeEntrySorter(t.Entries)) {
308+
return ErrEntriesNotSorted
309+
}
310+
282311
for _, entry := range t.Entries {
312+
if strings.IndexByte(entry.Name, 0) != -1 {
313+
return fmt.Errorf("malformed filename %q", entry.Name)
314+
}
283315
if _, err = fmt.Fprintf(w, "%o %s", entry.Mode, entry.Name); err != nil {
284316
return err
285317
}

plumbing/object/tree_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"io"
7+
"sort"
78
"testing"
89

910
fixtures "github.com/go-git/go-git-fixtures/v4"
@@ -220,6 +221,30 @@ func (o *SortReadCloser) Read(p []byte) (int, error) {
220221
return nw, nil
221222
}
222223

224+
func (s *TreeSuite) TestTreeEntriesSorted(c *C) {
225+
tree := &Tree{
226+
Entries: []TreeEntry{
227+
{"foo", filemode.Empty, plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d")},
228+
{"bar", filemode.Empty, plumbing.NewHash("c029517f6300c2da0f4b651b8642506cd6aaf45d")},
229+
{"baz", filemode.Empty, plumbing.NewHash("d029517f6300c2da0f4b651b8642506cd6aaf45d")},
230+
},
231+
}
232+
233+
{
234+
c.Assert(sort.IsSorted(TreeEntrySorter(tree.Entries)), Equals, false)
235+
obj := &plumbing.MemoryObject{}
236+
err := tree.Encode(obj)
237+
c.Assert(err, Equals, ErrEntriesNotSorted)
238+
}
239+
240+
{
241+
sort.Sort(TreeEntrySorter(tree.Entries))
242+
obj := &plumbing.MemoryObject{}
243+
err := tree.Encode(obj)
244+
c.Assert(err, IsNil)
245+
}
246+
}
247+
223248
func (s *TreeSuite) TestTreeDecodeEncodeIdempotent(c *C) {
224249
trees := []*Tree{
225250
{
@@ -231,6 +256,7 @@ func (s *TreeSuite) TestTreeDecodeEncodeIdempotent(c *C) {
231256
},
232257
}
233258
for _, tree := range trees {
259+
sort.Sort(TreeEntrySorter(tree.Entries))
234260
obj := &plumbing.MemoryObject{}
235261
err := tree.Encode(obj)
236262
c.Assert(err, IsNil)

0 commit comments

Comments
 (0)