Skip to content

Commit 058e1be

Browse files
committed
open & close
1 parent 91d0c9e commit 058e1be

File tree

2 files changed

+136
-15
lines changed

2 files changed

+136
-15
lines changed

packet.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@ func (p sshFxpClosePacket) MarshalBinary() ([]byte, error) {
287287
return marshalIdString(ssh_FXP_CLOSE, p.Id, p.Handle)
288288
}
289289

290+
func (p *sshFxpClosePacket) UnmarshalBinary(b []byte) error {
291+
return unmarshalIdString(b, &p.Id, &p.Handle)
292+
}
293+
290294
type sshFxpRemovePacket struct {
291295
Id uint32
292296
Filename string
@@ -335,6 +339,19 @@ func (p sshFxpOpenPacket) MarshalBinary() ([]byte, error) {
335339
return b, nil
336340
}
337341

342+
func (p *sshFxpOpenPacket) UnmarshalBinary(b []byte) (err error) {
343+
if p.Id, b, err = unmarshalUint32Safe(b); err != nil {
344+
return
345+
} else if p.Path, b, err = unmarshalStringSafe(b); err != nil {
346+
return
347+
} else if p.Pflags, b, err = unmarshalUint32Safe(b); err != nil {
348+
return
349+
} else if p.Flags, b, err = unmarshalUint32Safe(b); err != nil {
350+
return
351+
}
352+
return
353+
}
354+
338355
type sshFxpReadPacket struct {
339356
Id uint32
340357
Handle string
@@ -449,3 +466,27 @@ func (p sshFxpSetstatPacket) MarshalBinary() ([]byte, error) {
449466
b = marshal(b, p.Attrs)
450467
return b, nil
451468
}
469+
470+
type sshFxpHandlePacket struct {
471+
Id uint32
472+
Handle string
473+
}
474+
475+
func (p sshFxpHandlePacket) MarshalBinary() ([]byte, error) {
476+
b := []byte{ssh_FXP_HANDLE}
477+
b = marshalUint32(b, p.Id)
478+
b = marshalString(b, p.Handle)
479+
return b, nil
480+
}
481+
482+
type sshFxpStatusPacket struct {
483+
Id uint32
484+
StatusError
485+
}
486+
487+
func (p sshFxpStatusPacket) MarshalBinary() ([]byte, error) {
488+
b := []byte{ssh_FXP_STATUS}
489+
b = marshalUint32(b, p.Id)
490+
b = marshalStatus(b, p.StatusError)
491+
return b, nil
492+
}

server.go

Lines changed: 95 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,38 @@ type FileSystem interface {
1616
Mkdir(name string, perm os.FileMode) error
1717
}
1818

19+
type FileSystemOpen interface {
20+
FileSystem
21+
OpenFile(name string, flag int, perm os.FileMode) (file *os.File, err error)
22+
}
23+
24+
type FileSystemSFTPOpen interface {
25+
FileSystem
26+
OpenFile(path string, f int) (*File, error) // sftp package has a strange OpenFile method with no perm
27+
}
28+
29+
// common subset of os.File and sftp.File
30+
type svrFile interface {
31+
Chmod(mode os.FileMode) error
32+
Chown(uid, gid int) error
33+
Close() error
34+
Read(b []byte) (int, error)
35+
Seek(offset int64, whence int) (int64, error)
36+
Stat() (os.FileInfo, error)
37+
Truncate(size int64) error
38+
Write(b []byte) (int, error)
39+
// func (f *File) WriteTo(w io.Writer) (int64, error) // not in os
40+
// func (f *File) ReadFrom(r io.Reader) (int64, error) // not in os
41+
}
42+
1943
type nativeFs struct {
2044
}
2145

2246
func (nfs *nativeFs) Lstat(p string) (os.FileInfo, error) { return os.Lstat(p) }
2347
func (nfs *nativeFs) Mkdir(name string, perm os.FileMode) error { return os.Mkdir(name, perm) }
48+
func (nfs *nativeFs) OpenFile(name string, flag int, perm os.FileMode) (file *os.File, err error) {
49+
return os.OpenFile(name, flag, perm)
50+
}
2451

2552
type Server struct {
2653
in io.Reader
@@ -29,18 +56,36 @@ type Server struct {
2956
lastId uint32
3057
fs FileSystem
3158
pktChan chan serverRespondablePacket
32-
openFiles map[string]*svrFile
33-
openFilesLock *sync.Mutex
59+
openFiles map[string]svrFile
60+
openFilesLock *sync.RWMutex
61+
handleCount int
62+
}
63+
64+
func (svr *Server) nextHandle(f svrFile) string {
65+
svr.openFilesLock.Lock()
66+
defer svr.openFilesLock.Unlock()
67+
svr.handleCount++
68+
handle := fmt.Sprintf("%d", svr.handleCount)
69+
svr.openFiles[handle] = f
70+
return handle
71+
}
72+
73+
func (svr *Server) closeHandle(handle string) error {
74+
svr.openFilesLock.Lock()
75+
defer svr.openFilesLock.Unlock()
76+
if f, ok := svr.openFiles[handle]; ok {
77+
delete(svr.openFiles, handle)
78+
return f.Close()
79+
} else {
80+
return syscall.EBADF
81+
}
3482
}
3583

3684
type serverRespondablePacket interface {
3785
encoding.BinaryUnmarshaler
3886
respond(svr *Server) error
3987
}
4088

41-
type svrFile struct {
42-
}
43-
4489
// Creates a new server instance around the provided streams.
4590
// A subsequent call to Run() is required.
4691
func NewServer(in io.Reader, out io.Writer, rootDir string) (*Server, error) {
@@ -57,8 +102,8 @@ func NewServer(in io.Reader, out io.Writer, rootDir string) (*Server, error) {
57102
rootDir: rootDir,
58103
fs: &nativeFs{},
59104
pktChan: make(chan serverRespondablePacket, 4),
60-
openFiles: map[string]*svrFile{},
61-
openFilesLock: &sync.Mutex{},
105+
openFiles: map[string]svrFile{},
106+
openFilesLock: &sync.RWMutex{},
62107
}, nil
63108
}
64109

@@ -94,7 +139,9 @@ func (svr *Server) decodePacket(pktType fxp, pktBytes []byte) (serverRespondable
94139
pkt = &sshFxpLstatPacket{}
95140
case ssh_FXP_VERSION:
96141
case ssh_FXP_OPEN:
142+
pkt = &sshFxpOpenPacket{}
97143
case ssh_FXP_CLOSE:
144+
pkt = &sshFxpClosePacket{}
98145
case ssh_FXP_READ:
99146
case ssh_FXP_WRITE:
100147
case ssh_FXP_FSTAT:
@@ -170,16 +217,49 @@ func (p sshFxpMkdirPacket) respond(svr *Server) error {
170217
return svr.sendPacket(statusFromError(p.Id, err))
171218
}
172219

173-
type sshFxpStatusPacket struct {
174-
Id uint32
175-
StatusError
220+
func (p sshFxpOpenPacket) respond(svr *Server) error {
221+
osFlags := 0
222+
if p.Pflags&ssh_FXF_READ != 0 && p.Pflags&ssh_FXF_WRITE != 0 {
223+
osFlags |= os.O_RDWR
224+
} else if p.Pflags&ssh_FXF_READ != 0 {
225+
osFlags |= os.O_RDONLY
226+
} else if p.Pflags&ssh_FXF_WRITE != 0 {
227+
osFlags |= os.O_WRONLY
228+
}
229+
if p.Pflags&ssh_FXF_APPEND != 0 {
230+
osFlags |= os.O_APPEND
231+
}
232+
if p.Pflags&ssh_FXF_CREAT != 0 {
233+
osFlags |= os.O_CREATE
234+
}
235+
if p.Pflags&ssh_FXF_TRUNC != 0 {
236+
osFlags |= os.O_TRUNC
237+
}
238+
if p.Pflags&ssh_FXF_EXCL != 0 {
239+
osFlags |= os.O_EXCL
240+
}
241+
242+
if fso, ok := svr.fs.(FileSystemOpen); ok {
243+
if f, err := fso.OpenFile(p.Path, osFlags, 0644); err != nil {
244+
return svr.sendPacket(statusFromError(p.Id, err))
245+
} else {
246+
handle := svr.nextHandle(f)
247+
return svr.sendPacket(sshFxpHandlePacket{p.Id, handle})
248+
}
249+
} else if sftpo, ok := svr.fs.(FileSystemSFTPOpen); ok {
250+
if f, err := sftpo.OpenFile(p.Path, osFlags); err != nil {
251+
return svr.sendPacket(statusFromError(p.Id, err))
252+
} else {
253+
handle := svr.nextHandle(f)
254+
return svr.sendPacket(sshFxpHandlePacket{p.Id, handle})
255+
}
256+
} else {
257+
return svr.sendPacket(statusFromError(p.Id, fmt.Errorf("unknown filesystem backend")))
258+
}
176259
}
177260

178-
func (p sshFxpStatusPacket) MarshalBinary() ([]byte, error) {
179-
b := []byte{ssh_FXP_STATUS}
180-
b = marshalUint32(b, p.Id)
181-
b = marshalStatus(b, p.StatusError)
182-
return b, nil
261+
func (p sshFxpClosePacket) respond(svr *Server) error {
262+
return svr.sendPacket(statusFromError(p.Id, svr.closeHandle(p.Handle)))
183263
}
184264

185265
func statusFromError(id uint32, err error) sshFxpStatusPacket {

0 commit comments

Comments
 (0)