diff --git a/server.go b/server.go index 24f5f4e9..6df82ee1 100644 --- a/server.go +++ b/server.go @@ -80,6 +80,7 @@ type Server struct { openFilesLock sync.RWMutex handleCount int workDir string + winRoot bool } func (svr *Server) nextHandle(f file) string { @@ -162,6 +163,14 @@ func ReadOnly() ServerOption { } } +// WinRoot configures a Server to serve a virtual '/' for windows that lists all drives +func WinRoot() ServerOption { + return func(s *Server) error { + s.winRoot = true + return nil + } +} + // WithAllocator enable the allocator. // After processing a packet we keep in memory the allocated slices // and we reuse them for new packets. @@ -508,7 +517,7 @@ func (p *sshFxpOpenPacket) respond(svr *Server) responsePacket { osFlags |= os.O_EXCL } - f, err := openfile(svr.toLocalPath(p.Path), osFlags, 0o644) + f, err := svr.openfile(svr.toLocalPath(p.Path), osFlags, 0o644) if err != nil { return statusFromError(p.ID, err) } diff --git a/server_posix.go b/server_posix.go index 935a7aa2..6ca70199 100644 --- a/server_posix.go +++ b/server_posix.go @@ -8,6 +8,6 @@ import ( "os" ) -func openfile(path string, flag int, mode fs.FileMode) (file, error) { +func (s *Server) openfile(path string, flag int, mode fs.FileMode) (file, error) { return os.OpenFile(path, flag, mode) } diff --git a/server_windows.go b/server_windows.go index 5aabf05f..eb932eeb 100644 --- a/server_windows.go +++ b/server_windows.go @@ -18,7 +18,11 @@ func (s *Server) toLocalPath(p string) string { lp := filepath.FromSlash(p) - if path.IsAbs(p) { + if path.IsAbs(p) { // starts with '/' + if len(p) == 1 { + return `\\.\` // for openfile + } + tmp := lp for len(tmp) > 0 && tmp[0] == '\\' { tmp = tmp[1:] @@ -39,6 +43,11 @@ func (s *Server) toLocalPath(p string) string { // e.g. "/C:" to "C:\\" return tmp } + + if s.winRoot { + // Make it so that "/Windows" is not found, and "/c:/Windows" has to be used + return `\\.\` + tmp + } } return lp @@ -93,19 +102,17 @@ func newWinRoot() (*winRoot, error) { func (f *winRoot) Readdir(n int) ([]os.FileInfo, error) { drives := f.drives - if n > 0 { - if len(drives) > n { - drives = drives[:n] - } - f.drives = f.drives[len(drives):] - if len(drives) == 0 { - return nil, io.EOF - } + if n > 0 && len(drives) > n { + drives = drives[:n] + } + f.drives = f.drives[len(drives):] + if len(drives) == 0 { + return nil, io.EOF } var infos []os.FileInfo for _, drive := range drives { - fi, err := os.Stat(drive) + fi, err := os.Stat(drive + `\`) if err != nil { return nil, err } @@ -120,8 +127,8 @@ func (f *winRoot) Readdir(n int) ([]os.FileInfo, error) { return infos, nil } -func openfile(path string, flag int, mode fs.FileMode) (file, error) { - if path == "/" { +func (s *Server) openfile(path string, flag int, mode fs.FileMode) (file, error) { + if path == `\\.\` && s.winRoot { return newWinRoot() } return os.OpenFile(path, flag, mode)