mirror of https://github.com/pkg/sftp.git
request server: call Close() on ListerAt if it implements io.Closer
The ListerAt is stored in the Request state and reused across requests. Some implementations don't store the entire []os.FileInfo buffer in the ListerAt implementation but instead return an open file and get/return []os.FileInfo on request. For these implementation calling Close is required
This commit is contained in:
parent
46d90e3f96
commit
fbb0b8bdb3
|
@ -144,6 +144,8 @@ type NameLookupFileLister interface {
|
||||||
//
|
//
|
||||||
// If a populated entry implements [FileInfoExtendedData], extended attributes will also be returned to the client.
|
// If a populated entry implements [FileInfoExtendedData], extended attributes will also be returned to the client.
|
||||||
//
|
//
|
||||||
|
// The request server code will call Close() on ListerAt if an io.Closer type assertion succeeds.
|
||||||
|
//
|
||||||
// Note in cases of an error, the error text will be sent to the client.
|
// Note in cases of an error, the error text will be sent to the client.
|
||||||
type ListerAt interface {
|
type ListerAt interface {
|
||||||
ListAt([]os.FileInfo, int64) (int, error)
|
ListAt([]os.FileInfo, int64) (int, error)
|
||||||
|
|
|
@ -793,6 +793,37 @@ func TestRequestReaddir(t *testing.T) {
|
||||||
checkRequestServerAllocator(t, p)
|
checkRequestServerAllocator(t, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testListerAtCloser struct {
|
||||||
|
isClosed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *testListerAtCloser) ListAt([]os.FileInfo, int64) (int, error) {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *testListerAtCloser) Close() error {
|
||||||
|
l.isClosed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRequestServerListerAtCloser(t *testing.T) {
|
||||||
|
p := clientRequestServerPair(t)
|
||||||
|
defer p.Close()
|
||||||
|
|
||||||
|
handle, err := p.cli.opendir(context.Background(), "/")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, p.svr.openRequests, 1)
|
||||||
|
req, ok := p.svr.getRequest(handle)
|
||||||
|
require.True(t, ok)
|
||||||
|
listerAt := &testListerAtCloser{}
|
||||||
|
req.setListerAt(listerAt)
|
||||||
|
assert.NotNil(t, req.state.getListerAt())
|
||||||
|
err = p.cli.close(handle)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.Len(t, p.svr.openRequests, 0)
|
||||||
|
assert.True(t, listerAt.isClosed)
|
||||||
|
}
|
||||||
|
|
||||||
func TestRequestStatVFS(t *testing.T) {
|
func TestRequestStatVFS(t *testing.T) {
|
||||||
if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
|
if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
|
||||||
t.Skip("StatVFS is implemented on linux and darwin")
|
t.Skip("StatVFS is implemented on linux and darwin")
|
||||||
|
|
20
request.go
20
request.go
|
@ -121,6 +121,22 @@ func (s *state) getListerAt() ListerAt {
|
||||||
return s.listerAt
|
return s.listerAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *state) closeListerAt() error {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if s.listerAt != nil {
|
||||||
|
if c, ok := s.listerAt.(io.Closer); ok {
|
||||||
|
err = c.Close()
|
||||||
|
}
|
||||||
|
s.listerAt = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Request contains the data and state for the incoming service request.
|
// Request contains the data and state for the incoming service request.
|
||||||
type Request struct {
|
type Request struct {
|
||||||
// Get, Put, Setstat, Stat, Rename, Remove
|
// Get, Put, Setstat, Stat, Rename, Remove
|
||||||
|
@ -230,9 +246,9 @@ func (r *Request) close() error {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
rd, wr, rw := r.getAllReaderWriters()
|
err := r.state.closeListerAt()
|
||||||
|
|
||||||
var err error
|
rd, wr, rw := r.getAllReaderWriters()
|
||||||
|
|
||||||
// Close errors on a Writer are far more likely to be the important one.
|
// Close errors on a Writer are far more likely to be the important one.
|
||||||
// As they can be information that there was a loss of data.
|
// As they can be information that there was a loss of data.
|
||||||
|
|
Loading…
Reference in New Issue