From 872d2f0d7390829d460fc3ca0f24e88e9ffc42d2 Mon Sep 17 00:00:00 2001 From: Antti Aalto Date: Fri, 31 Mar 2017 23:26:41 +0300 Subject: [PATCH] Windows: Fix ssh --- src/borg/platform/__init__.py | 1 + src/borg/platform/windows.pyx | 23 +++++++++++++++++++++++ src/borg/remote.py | 33 ++++++++++++++++++++++++++++----- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/borg/platform/__init__.py b/src/borg/platform/__init__.py index 8126ffd96..059348956 100644 --- a/src/borg/platform/__init__.py +++ b/src/borg/platform/__init__.py @@ -28,3 +28,4 @@ elif sys.platform == 'win32': # pragma: windows only from .windows import sync_dir from .windows import get_owner, set_owner from .windows import get_ads + from .windows import select diff --git a/src/borg/platform/windows.pyx b/src/borg/platform/windows.pyx index 31a502f4e..1cf9004b0 100644 --- a/src/borg/platform/windows.pyx +++ b/src/borg/platform/windows.pyx @@ -9,6 +9,16 @@ import array import platform +import ctypes +import ctypes.wintypes +import msvcrt + +PeekNamedPipe = ctypes.windll.kernel32.PeekNamedPipe +PeekNamedPipe.argtypes = [ctypes.wintypes.HANDLE, ctypes.c_void_p, ctypes.wintypes.DWORD, + ctypes.POINTER(ctypes.wintypes.DWORD), ctypes.POINTER(ctypes.wintypes.DWORD), + ctypes.POINTER(ctypes.wintypes.DWORD)] +PeekNamedPipe.restype = ctypes.c_bool + API_VERSION = 3 @@ -544,3 +554,16 @@ def get_ads(path): FindClose(searchHandle) PyMem_Free(cstrPath) return ret + + +def select(rlist, wlist, xlist, timeout=0): + retRlist = [] + retXlist = [] + for pipe in rlist: + size = ctypes.wintypes.DWORD(0) + if not PeekNamedPipe(msvcrt.get_osfhandle(pipe), None, 0, None, ctypes.byref(size), None): + if size.value == 0 and pipe in xlist: + retXlist.append(pipe) + if size.value > 0: + retRlist.append(pipe) + return retRlist, wlist, retXlist diff --git a/src/borg/remote.py b/src/borg/remote.py index 13146d7b8..4f2bfbc1e 100644 --- a/src/borg/remote.py +++ b/src/borg/remote.py @@ -2,6 +2,8 @@ import errno import sys if sys.platform != 'win32': import fcntl +else: + import shutil import logging import os import select @@ -19,6 +21,12 @@ from .helpers import sysinfo from .helpers import bin_to_hex from .repository import Repository +if sys.platform == 'win32': + from .platform import select as windowsSelect + select.select = windowsSelect + class NoSSHClient(Error): + """Could not find supported ssh client. Supported clients are {}.""" + RPC_PROTOCOL_VERSION = 2 BUFSIZE = 10 * 1024 * 1024 @@ -237,12 +245,27 @@ class RemoteRepository: def ssh_cmd(self, location): """return a ssh command line that can be prefixed to a borg command line""" args = shlex.split(os.environ.get('BORG_RSH', 'ssh')) - if location.port: - args += ['-p', str(location.port)] - if location.user: - args.append('%s@%s' % (location.user, location.host)) + if sys.platform == 'win32' and 'BORG_RSH' not in os.environ: + if shutil.which('ssh') is not None: + args = ['ssh'] + elif shutil.which('plink') is not None: + args = ['plink', '-ssh', '-batch'] + else: + raise NoSSHClient('ssh and plink') + if args[0] == 'plink': + if location.port: + args += ['-P', str(location.port)] + if location.user: + args.append('%s@%s' % (location.user, location.host)) + else: + args.append('%s' % location.host) else: - args.append('%s' % location.host) + if location.port: + args += ['-p', str(location.port)] + if location.user: + args.append('%s@%s' % (location.user, location.host)) + else: + args.append('%s' % location.host) return args def call(self, cmd, *args, **kw):