Browse Source

Windows: Fix ssh

Antti Aalto 8 years ago
parent
commit
872d2f0d73
3 changed files with 52 additions and 5 deletions
  1. 1 0
      src/borg/platform/__init__.py
  2. 23 0
      src/borg/platform/windows.pyx
  3. 28 5
      src/borg/remote.py

+ 1 - 0
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

+ 23 - 0
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

+ 28 - 5
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):