|
@@ -2,17 +2,22 @@ import argparse
|
|
from binascii import hexlify
|
|
from binascii import hexlify
|
|
from collections import namedtuple, deque
|
|
from collections import namedtuple, deque
|
|
from functools import wraps, partial
|
|
from functools import wraps, partial
|
|
-import grp
|
|
|
|
|
|
+import sys
|
|
|
|
+if sys.platform != 'win32':
|
|
|
|
+ import grp
|
|
|
|
+ import pwd
|
|
|
|
+else:
|
|
|
|
+ import posixpath
|
|
import hashlib
|
|
import hashlib
|
|
from itertools import islice
|
|
from itertools import islice
|
|
import os
|
|
import os
|
|
import os.path
|
|
import os.path
|
|
import stat
|
|
import stat
|
|
import textwrap
|
|
import textwrap
|
|
-import pwd
|
|
|
|
|
|
+
|
|
import re
|
|
import re
|
|
from shutil import get_terminal_size
|
|
from shutil import get_terminal_size
|
|
-import sys
|
|
|
|
|
|
+
|
|
from string import Formatter
|
|
from string import Formatter
|
|
import platform
|
|
import platform
|
|
import time
|
|
import time
|
|
@@ -37,7 +42,6 @@ import msgpack.fallback
|
|
|
|
|
|
import socket
|
|
import socket
|
|
|
|
|
|
-
|
|
|
|
# meta dict, data bytes
|
|
# meta dict, data bytes
|
|
_Chunk = namedtuple('_Chunk', 'meta data')
|
|
_Chunk = namedtuple('_Chunk', 'meta data')
|
|
|
|
|
|
@@ -387,10 +391,16 @@ class PathPrefixPattern(PatternBase):
|
|
PREFIX = "pp"
|
|
PREFIX = "pp"
|
|
|
|
|
|
def _prepare(self, pattern):
|
|
def _prepare(self, pattern):
|
|
- self.pattern = os.path.normpath(pattern).rstrip(os.path.sep) + os.path.sep
|
|
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ self.pattern = os.path.normpath(pattern).rstrip(os.path.sep) + os.path.sep
|
|
|
|
+ else:
|
|
|
|
+ self.pattern = posixpath.normpath(pattern).rstrip(posixpath.sep) + posixpath.sep
|
|
|
|
|
|
def _match(self, path):
|
|
def _match(self, path):
|
|
- return (path + os.path.sep).startswith(self.pattern)
|
|
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ return (path + os.path.sep).startswith(self.pattern)
|
|
|
|
+ else:
|
|
|
|
+ return (path + posixpath.sep).startswith(self.pattern)
|
|
|
|
|
|
|
|
|
|
class FnmatchPattern(PatternBase):
|
|
class FnmatchPattern(PatternBase):
|
|
@@ -682,7 +692,10 @@ def memoize(function):
|
|
@memoize
|
|
@memoize
|
|
def uid2user(uid, default=None):
|
|
def uid2user(uid, default=None):
|
|
try:
|
|
try:
|
|
- return pwd.getpwuid(uid).pw_name
|
|
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ return pwd.getpwuid(uid).pw_name
|
|
|
|
+ else:
|
|
|
|
+ return os.getlogin()
|
|
except KeyError:
|
|
except KeyError:
|
|
return default
|
|
return default
|
|
|
|
|
|
@@ -690,7 +703,10 @@ def uid2user(uid, default=None):
|
|
@memoize
|
|
@memoize
|
|
def user2uid(user, default=None):
|
|
def user2uid(user, default=None):
|
|
try:
|
|
try:
|
|
- return user and pwd.getpwnam(user).pw_uid
|
|
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ return user and pwd.getpwnam(user).pw_uid
|
|
|
|
+ else:
|
|
|
|
+ return user and 0
|
|
except KeyError:
|
|
except KeyError:
|
|
return default
|
|
return default
|
|
|
|
|
|
@@ -698,17 +714,32 @@ def user2uid(user, default=None):
|
|
@memoize
|
|
@memoize
|
|
def gid2group(gid, default=None):
|
|
def gid2group(gid, default=None):
|
|
try:
|
|
try:
|
|
- return grp.getgrgid(gid).gr_name
|
|
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ return grp.getgrgid(gid).gr_name
|
|
|
|
+ else:
|
|
|
|
+ return ''
|
|
except KeyError:
|
|
except KeyError:
|
|
return default
|
|
return default
|
|
|
|
|
|
|
|
|
|
@memoize
|
|
@memoize
|
|
def group2gid(group, default=None):
|
|
def group2gid(group, default=None):
|
|
- try:
|
|
|
|
- return group and grp.getgrnam(group).gr_gid
|
|
|
|
- except KeyError:
|
|
|
|
- return default
|
|
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ if group == '':
|
|
|
|
+ return 0 # From windows
|
|
|
|
+ try:
|
|
|
|
+ return group and grp.getgrnam(group).gr_gid
|
|
|
|
+ except KeyError:
|
|
|
|
+ return default
|
|
|
|
+ else:
|
|
|
|
+ return 0
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def getuid():
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ return os.getuid()
|
|
|
|
+ else:
|
|
|
|
+ return 0
|
|
|
|
|
|
|
|
|
|
def posix_acl_use_stored_uid_gid(acl):
|
|
def posix_acl_use_stored_uid_gid(acl):
|
|
@@ -748,8 +779,13 @@ class Location:
|
|
ssh_re = re.compile(r'(?P<proto>ssh)://(?:(?P<user>[^@]+)@)?'
|
|
ssh_re = re.compile(r'(?P<proto>ssh)://(?:(?P<user>[^@]+)@)?'
|
|
r'(?P<host>[^:/#]+)(?::(?P<port>\d+))?'
|
|
r'(?P<host>[^:/#]+)(?::(?P<port>\d+))?'
|
|
r'(?P<path>[^:]+)(?:::(?P<archive>[^/]+))?$')
|
|
r'(?P<path>[^:]+)(?:::(?P<archive>[^/]+))?$')
|
|
- file_re = re.compile(r'(?P<proto>file)://'
|
|
|
|
- r'(?P<path>[^:]+)(?:::(?P<archive>[^/]+))?$')
|
|
|
|
|
|
+ file_re = None
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ file_re = re.compile(r'(?P<proto>file)://'
|
|
|
|
+ r'(?P<path>[^:]+)(?:::(?P<archive>[^/]+))?$')
|
|
|
|
+ else:
|
|
|
|
+ file_re = re.compile(r'((?P<proto>file)://)?'
|
|
|
|
+ r'(?P<drive>[a-zA-Z])?:[\\/](?P<path>[^:]+)(?:::(?P<archive>[^/]+))?$')
|
|
scp_re = re.compile(r'((?:(?P<user>[^@]+)@)?(?P<host>[^:/]+):)?'
|
|
scp_re = re.compile(r'((?:(?P<user>[^@]+)@)?(?P<host>[^:/]+):)?'
|
|
r'(?P<path>[^:]+)(?:::(?P<archive>[^/]+))?$')
|
|
r'(?P<path>[^:]+)(?:::(?P<archive>[^/]+))?$')
|
|
# get the repo from BORG_RE env and the optional archive from param.
|
|
# get the repo from BORG_RE env and the optional archive from param.
|
|
@@ -772,7 +808,7 @@ class Location:
|
|
'hostname': socket.gethostname(),
|
|
'hostname': socket.gethostname(),
|
|
'now': current_time.now(),
|
|
'now': current_time.now(),
|
|
'utcnow': current_time.utcnow(),
|
|
'utcnow': current_time.utcnow(),
|
|
- 'user': uid2user(os.getuid(), os.getuid())
|
|
|
|
|
|
+ 'user': uid2user(getuid(), getuid())
|
|
}
|
|
}
|
|
return format_line(text, data)
|
|
return format_line(text, data)
|
|
|
|
|
|
@@ -794,26 +830,41 @@ class Location:
|
|
return True
|
|
return True
|
|
|
|
|
|
def _parse(self, text):
|
|
def _parse(self, text):
|
|
|
|
+ if sys.platform == 'win32':
|
|
|
|
+ m = self.file_re.match(text)
|
|
|
|
+ if m:
|
|
|
|
+ self.proto = m.group('proto')
|
|
|
|
+ self.path = posixpath.normpath(m.group('drive') + ":\\" + m.group('path'))
|
|
|
|
+ self.archive = m.group('archive')
|
|
|
|
+ return True
|
|
|
|
+
|
|
m = self.ssh_re.match(text)
|
|
m = self.ssh_re.match(text)
|
|
if m:
|
|
if m:
|
|
self.proto = m.group('proto')
|
|
self.proto = m.group('proto')
|
|
self.user = m.group('user')
|
|
self.user = m.group('user')
|
|
self.host = m.group('host')
|
|
self.host = m.group('host')
|
|
self.port = m.group('port') and int(m.group('port')) or None
|
|
self.port = m.group('port') and int(m.group('port')) or None
|
|
- self.path = os.path.normpath(m.group('path'))
|
|
|
|
- self.archive = m.group('archive')
|
|
|
|
- return True
|
|
|
|
- m = self.file_re.match(text)
|
|
|
|
- if m:
|
|
|
|
- self.proto = m.group('proto')
|
|
|
|
- self.path = os.path.normpath(m.group('path'))
|
|
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ self.path = os.path.normpath(m.group('path'))
|
|
|
|
+ else:
|
|
|
|
+ self.path = posixpath.normpath(m.group('path'))
|
|
self.archive = m.group('archive')
|
|
self.archive = m.group('archive')
|
|
return True
|
|
return True
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ m = self.file_re.match(text)
|
|
|
|
+ if m:
|
|
|
|
+ self.proto = m.group('proto')
|
|
|
|
+ self.path = os.path.normpath(m.group('path'))
|
|
|
|
+ self.archive = m.group('archive')
|
|
|
|
+ return True
|
|
m = self.scp_re.match(text)
|
|
m = self.scp_re.match(text)
|
|
if m:
|
|
if m:
|
|
self.user = m.group('user')
|
|
self.user = m.group('user')
|
|
self.host = m.group('host')
|
|
self.host = m.group('host')
|
|
- self.path = os.path.normpath(m.group('path'))
|
|
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ self.path = os.path.normpath(m.group('path'))
|
|
|
|
+ else:
|
|
|
|
+ self.path = posixpath.normpath(m.group('path'))
|
|
self.archive = m.group('archive')
|
|
self.archive = m.group('archive')
|
|
self.proto = self.host and 'ssh' or 'file'
|
|
self.proto = self.host and 'ssh' or 'file'
|
|
return True
|
|
return True
|
|
@@ -889,14 +940,24 @@ def remove_surrogates(s, errors='replace'):
|
|
"""
|
|
"""
|
|
return s.encode('utf-8', errors).decode('utf-8')
|
|
return s.encode('utf-8', errors).decode('utf-8')
|
|
|
|
|
|
-
|
|
|
|
-_safe_re = re.compile(r'^((\.\.)?/+)+')
|
|
|
|
|
|
+_safe_re = None
|
|
|
|
+if sys.platform != 'win32':
|
|
|
|
+ _safe_re = re.compile(r'^((\.\.)?/+)+')
|
|
|
|
+else:
|
|
|
|
+ _safe_re = re.compile(r'^((\.\.)?[/\\]+)+')
|
|
|
|
|
|
|
|
|
|
def make_path_safe(path):
|
|
def make_path_safe(path):
|
|
"""Make path safe by making it relative and local
|
|
"""Make path safe by making it relative and local
|
|
"""
|
|
"""
|
|
- return _safe_re.sub('', path) or '.'
|
|
|
|
|
|
+ if sys.platform != 'win32':
|
|
|
|
+ return _safe_re.sub('', path) or '.'
|
|
|
|
+ else:
|
|
|
|
+ tail = path
|
|
|
|
+ if len(path) > 2 and (path[0:2] == '//' or path[0:2] == '\\\\' or path[1] == ':'):
|
|
|
|
+ drive, tail = os.path.splitdrive(path)
|
|
|
|
+ tail = tail.replace('\\', '/')
|
|
|
|
+ return posixpath.normpath(_safe_re.sub('', tail) or '.')
|
|
|
|
|
|
|
|
|
|
def daemonize():
|
|
def daemonize():
|