Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 94ddfeb

Browse files
authored
Merge pull request #1036 from jfontan/fix/capabilities-setref
storage/dotgit: use fs capabilities in setRef
2 parents 443abf8 + 681855b commit 94ddfeb

File tree

3 files changed

+73
-50
lines changed

3 files changed

+73
-50
lines changed

storage/filesystem/dotgit/dotgit_setref.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
1-
// +build !norwfs
2-
31
package dotgit
42

53
import (
4+
"fmt"
65
"os"
76

87
"gopkg.in/src-d/go-git.v4/plumbing"
98
"gopkg.in/src-d/go-git.v4/utils/ioutil"
9+
10+
"gopkg.in/src-d/go-billy.v4"
1011
)
1112

1213
func (d *DotGit) setRef(fileName, content string, old *plumbing.Reference) (err error) {
14+
if billy.CapabilityCheck(d.fs, billy.ReadAndWriteCapability) {
15+
return d.setRefRwfs(fileName, content, old)
16+
}
17+
18+
return d.setRefNorwfs(fileName, content, old)
19+
}
20+
21+
func (d *DotGit) setRefRwfs(fileName, content string, old *plumbing.Reference) (err error) {
1322
// If we are not checking an old ref, just truncate the file.
1423
mode := os.O_RDWR | os.O_CREATE
1524
if old == nil {
@@ -41,3 +50,41 @@ func (d *DotGit) setRef(fileName, content string, old *plumbing.Reference) (err
4150
_, err = f.Write([]byte(content))
4251
return err
4352
}
53+
54+
// There are some filesystems that don't support opening files in RDWD mode.
55+
// In these filesystems the standard SetRef function can not be used as it
56+
// reads the reference file to check that it's not modified before updating it.
57+
//
58+
// This version of the function writes the reference without extra checks
59+
// making it compatible with these simple filesystems. This is usually not
60+
// a problem as they should be accessed by only one process at a time.
61+
func (d *DotGit) setRefNorwfs(fileName, content string, old *plumbing.Reference) error {
62+
_, err := d.fs.Stat(fileName)
63+
if err == nil && old != nil {
64+
fRead, err := d.fs.Open(fileName)
65+
if err != nil {
66+
return err
67+
}
68+
69+
ref, err := d.readReferenceFrom(fRead, old.Name().String())
70+
fRead.Close()
71+
72+
if err != nil {
73+
return err
74+
}
75+
76+
if ref.Hash() != old.Hash() {
77+
return fmt.Errorf("reference has changed concurrently")
78+
}
79+
}
80+
81+
f, err := d.fs.Create(fileName)
82+
if err != nil {
83+
return err
84+
}
85+
86+
defer f.Close()
87+
88+
_, err = f.Write([]byte(content))
89+
return err
90+
}

storage/filesystem/dotgit/dotgit_setref_norwfs.go

Lines changed: 0 additions & 47 deletions
This file was deleted.

storage/filesystem/dotgit/dotgit_test.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,26 @@ func (s *SuiteDotGit) TestSetRefs(c *C) {
5757
fs := osfs.New(tmp)
5858
dir := New(fs)
5959

60+
testSetRefs(c, dir)
61+
}
62+
63+
func (s *SuiteDotGit) TestSetRefsNorwfs(c *C) {
64+
tmp, err := ioutil.TempDir("", "dot-git")
65+
c.Assert(err, IsNil)
66+
defer os.RemoveAll(tmp)
67+
68+
fs := osfs.New(tmp)
69+
dir := New(&norwfs{fs})
70+
71+
testSetRefs(c, dir)
72+
}
73+
74+
func testSetRefs(c *C, dir *DotGit) {
6075
firstFoo := plumbing.NewReferenceFromStrings(
6176
"refs/heads/foo",
6277
"e8d3ffab552895c19b9fcf7aa264d277cde33881",
6378
)
64-
err = dir.SetRef(firstFoo, nil)
79+
err := dir.SetRef(firstFoo, nil)
6580

6681
c.Assert(err, IsNil)
6782

@@ -795,3 +810,11 @@ func (s *SuiteDotGit) TestAlternates(c *C) {
795810
}
796811
c.Assert(dotgits[1].fs.Root(), Equals, expectedPath)
797812
}
813+
814+
type norwfs struct {
815+
billy.Filesystem
816+
}
817+
818+
func (f *norwfs) Capabilities() billy.Capability {
819+
return billy.Capabilities(f.Filesystem) &^ billy.ReadAndWriteCapability
820+
}

0 commit comments

Comments
 (0)