From d733da7b444d9b0ac92b13b50b69e15d1c13e224 Mon Sep 17 00:00:00 2001 From: Cassondra Foesch Date: Tue, 29 Jun 2021 15:15:13 +0000 Subject: [PATCH 1/2] [bugfix] plan9 compile fails because of typo --- stat_plan9.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stat_plan9.go b/stat_plan9.go index 418f121c..52da0207 100644 --- a/stat_plan9.go +++ b/stat_plan9.go @@ -105,5 +105,5 @@ func fromFileMode(mode os.FileMode) uint32 { const ( s_ISUID = 04000 s_ISGID = 02000 - S_ISVTX = 01000 + s_ISVTX = 01000 ) From 71618243c4009fec223ca7537d49b5f1eb0697e5 Mon Sep 17 00:00:00 2001 From: Cassondra Foesch Date: Tue, 29 Jun 2021 15:16:15 +0000 Subject: [PATCH 2/2] deconvert encoded paths on windows servers --- request-plan9.go | 23 ++++++++++++++++++++++- request-server.go | 4 ++-- request-unix.go | 4 ++++ request_windows.go | 35 ++++++++++++++++++++++++++++++++++- server.go | 24 ++++++++++++++---------- 5 files changed, 76 insertions(+), 14 deletions(-) diff --git a/request-plan9.go b/request-plan9.go index 0074e8a3..2444da59 100644 --- a/request-plan9.go +++ b/request-plan9.go @@ -2,7 +2,11 @@ package sftp -import "syscall" +import ( + "path" + "path/filepath" + "syscall" +) func fakeFileInfoSys() interface{} { return &syscall.Dir{} @@ -11,3 +15,20 @@ func fakeFileInfoSys() interface{} { func testOsSys(sys interface{}) error { return nil } + +func toLocalPath(p string) string { + lp := filepath.FromSlash(p) + + if path.IsAbs(p) { + tmp := lp[1:] + + if filepath.IsAbs(tmp) { + // If the FromSlash without any starting slashes is absolute, + // then we have a filepath encoded with a prefix '/'. + // e.g. "/#s/boot" to "#s/boot" + return tmp + } + } + + return lp +} diff --git a/request-server.go b/request-server.go index b58aefce..63193c35 100644 --- a/request-server.go +++ b/request-server.go @@ -288,9 +288,9 @@ func cleanPath(p string) string { } func cleanPathWithBase(base, p string) string { - p = filepath.ToSlash(p) + p = filepath.ToSlash(filepath.Clean(p)) if !path.IsAbs(p) { return path.Join(base, p) } - return path.Clean(p) + return p } diff --git a/request-unix.go b/request-unix.go index d30b2569..50b08a38 100644 --- a/request-unix.go +++ b/request-unix.go @@ -21,3 +21,7 @@ func testOsSys(sys interface{}) error { } return nil } + +func toLocalPath(p string) string { + return p +} diff --git a/request_windows.go b/request_windows.go index 94d306b6..1f6d3df1 100644 --- a/request_windows.go +++ b/request_windows.go @@ -1,6 +1,10 @@ package sftp -import "syscall" +import ( + "path" + "path/filepath" + "syscall" +) func fakeFileInfoSys() interface{} { return syscall.Win32FileAttributeData{} @@ -9,3 +13,32 @@ func fakeFileInfoSys() interface{} { func testOsSys(sys interface{}) error { return nil } + +func toLocalPath(p string) string { + lp := filepath.FromSlash(p) + + if path.IsAbs(p) { + tmp := lp + for len(tmp) > 0 && tmp[0] == '\\' { + tmp = tmp[1:] + } + + if filepath.IsAbs(tmp) { + // If the FromSlash without any starting slashes is absolute, + // then we have a filepath encoded with a prefix '/'. + // e.g. "/C:/Windows" to "C:\\Windows" + return tmp + } + + tmp += "\\" + + if filepath.IsAbs(tmp) { + // If the FromSlash without any starting slashes but with extra end slash is absolute, + // then we have a filepath encoded with a prefix '/' and a dropped '/' at the end. + // e.g. "/C:" to "C:\\" + return tmp + } + } + + return lp +} diff --git a/server.go b/server.go index 909563f0..2da7d79b 100644 --- a/server.go +++ b/server.go @@ -175,7 +175,7 @@ func handlePacket(s *Server, p orderedRequest) error { } case *sshFxpStatPacket: // stat the requested file - info, err := os.Stat(p.Path) + info, err := os.Stat(toLocalPath(p.Path)) rpkt = &sshFxpStatResponse{ ID: p.ID, info: info, @@ -185,7 +185,7 @@ func handlePacket(s *Server, p orderedRequest) error { } case *sshFxpLstatPacket: // stat the requested file - info, err := os.Lstat(p.Path) + info, err := os.Lstat(toLocalPath(p.Path)) rpkt = &sshFxpStatResponse{ ID: p.ID, info: info, @@ -209,24 +209,24 @@ func handlePacket(s *Server, p orderedRequest) error { } case *sshFxpMkdirPacket: // TODO FIXME: ignore flags field - err := os.Mkdir(p.Path, 0755) + err := os.Mkdir(toLocalPath(p.Path), 0755) rpkt = statusFromError(p.ID, err) case *sshFxpRmdirPacket: - err := os.Remove(p.Path) + err := os.Remove(toLocalPath(p.Path)) rpkt = statusFromError(p.ID, err) case *sshFxpRemovePacket: - err := os.Remove(p.Filename) + err := os.Remove(toLocalPath(p.Filename)) rpkt = statusFromError(p.ID, err) case *sshFxpRenamePacket: - err := os.Rename(p.Oldpath, p.Newpath) + err := os.Rename(toLocalPath(p.Oldpath), toLocalPath(p.Newpath)) rpkt = statusFromError(p.ID, err) case *sshFxpSymlinkPacket: - err := os.Symlink(p.Targetpath, p.Linkpath) + err := os.Symlink(toLocalPath(p.Targetpath), toLocalPath(p.Linkpath)) rpkt = statusFromError(p.ID, err) case *sshFxpClosePacket: rpkt = statusFromError(p.ID, s.closeHandle(p.Handle)) case *sshFxpReadlinkPacket: - f, err := os.Readlink(p.Path) + f, err := os.Readlink(toLocalPath(p.Path)) rpkt = &sshFxpNamePacket{ ID: p.ID, NameAttrs: []*sshFxpNameAttr{ @@ -241,7 +241,7 @@ func handlePacket(s *Server, p orderedRequest) error { rpkt = statusFromError(p.ID, err) } case *sshFxpRealpathPacket: - f, err := filepath.Abs(p.Path) + f, err := filepath.Abs(toLocalPath(p.Path)) f = cleanPath(f) rpkt = &sshFxpNamePacket{ ID: p.ID, @@ -257,6 +257,8 @@ func handlePacket(s *Server, p orderedRequest) error { rpkt = statusFromError(p.ID, err) } case *sshFxpOpendirPacket: + p.Path = toLocalPath(p.Path) + if stat, err := os.Stat(p.Path); err != nil { rpkt = statusFromError(p.ID, err) } else if !stat.IsDir() { @@ -445,7 +447,7 @@ func (p *sshFxpOpenPacket) respond(svr *Server) responsePacket { osFlags |= os.O_EXCL } - f, err := os.OpenFile(p.Path, osFlags, 0644) + f, err := os.OpenFile(toLocalPath(p.Path), osFlags, 0644) if err != nil { return statusFromError(p.ID, err) } @@ -482,6 +484,8 @@ func (p *sshFxpSetstatPacket) respond(svr *Server) responsePacket { b := p.Attrs.([]byte) var err error + p.Path = toLocalPath(p.Path) + debug("setstat name \"%s\"", p.Path) if (p.Flags & sshFileXferAttrSize) != 0 { var size uint64