Skip to content

Commit

Permalink
Add Client.Sync method
Browse files Browse the repository at this point in the history
  • Loading branch information
greatroar committed Oct 23, 2020
1 parent fcaa492 commit e5bb489
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
20 changes: 20 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,26 @@ func (f *File) Chmod(mode os.FileMode) error {
return f.c.Chmod(f.path, mode)
}

// Sync requests a flush of the contents of a File to stable storage.
//
// Sync requires the server to support the fsync@openssh.com extension.
func (f *File) Sync() error {
id := f.c.nextID()
typ, data, err := f.c.sendPacket(sshFxpFsyncPacket{
ID: id,
Handle: f.handle,
})

switch {
case err != nil:
return err
case typ == sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return &unexpectedPacketErr{want: sshFxpStatus, got: typ}
}
}

// Truncate sets the size of the current file. Although it may be safely assumed
// that if the size is less than its current size it will be truncated to fit,
// the SFTP protocol does not specify what behavior the server should do when setting
Expand Down
42 changes: 42 additions & 0 deletions client_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"time"

"github.com/kr/fs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

const (
Expand Down Expand Up @@ -1434,6 +1436,46 @@ func clientReadDeadlock(t *testing.T, N int, badfunc func(*File)) {
badfunc(r)
}

func TestClientSyncGo(t *testing.T) {
err := testClientSync(t)

// Since Server does not support the fsync extension, we can only
// check that we get the right error.
require.NotNil(t, err)

switch err := err.(type) {
case *StatusError:
assert.Equal(t, ErrSSHFxOpUnsupported, err.FxCode())
default:
t.Error(err)
}
}

func TestClientSyncSFTP(t *testing.T) {
if *testServerImpl {
t.Skipf("skipping with -testserver")
}
err := testClientSync(t)
assert.Nil(t, err)
}

func testClientSync(t *testing.T) error {
sftp, cmd := testClient(t, READWRITE, NODELAY)
defer cmd.Wait()
defer sftp.Close()

d, err := ioutil.TempDir("", "sftptest")
require.Nil(t, err)
defer os.RemoveAll(d)

f := path.Join(d, "syncTest")
w, err := sftp.Create(f)
require.Nil(t, err)
defer w.Close()

return w.Sync()
}

// taken from github.com/kr/fs/walk_test.go

type Node struct {
Expand Down
20 changes: 20 additions & 0 deletions packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,26 @@ func (p *StatVFS) MarshalBinary() ([]byte, error) {
return buf.Bytes(), err
}

type sshFxpFsyncPacket struct {
ID uint32
Handle string
}

func (p sshFxpFsyncPacket) id() uint32 { return p.ID }

func (p sshFxpFsyncPacket) MarshalBinary() ([]byte, error) {
l := 1 + 4 + // type (byte) + ID (uint32)
4 + len("fsync@openssh.com") +
4 + len(p.Handle)

b := make([]byte, 0, l)
b = append(b, sshFxpExtended)
b = marshalUint32(b, p.ID)
b = marshalString(b, "fsync@openssh.com")
b = marshalString(b, p.Handle)
return b, nil
}

type sshFxpExtendedPacket struct {
ID uint32
ExtendedRequest string
Expand Down

0 comments on commit e5bb489

Please sign in to comment.