13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
21
S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
25
25
from bzrlib.lazy_import import lazy_import
26
26
lazy_import(globals(), """
28
27
from datetime import datetime
30
from ntpath import (abspath as _nt_abspath,
32
normpath as _nt_normpath,
33
realpath as _nt_realpath,
34
splitdrive as _nt_splitdrive,
31
# We need to import both shutil and rmtree as we export the later on posix
32
# and need the former on windows
34
from shutil import rmtree
37
# We need to import both tempfile and mkdtemp as we export the later on posix
38
# and need the former on windows
42
from tempfile import (
40
from tempfile import mkdtemp
47
43
from bzrlib import (
54
# sha and md5 modules are deprecated in python2.6 but hashlib is available as
56
if sys.version_info < (2, 5):
57
import md5 as _mod_md5
59
import sha as _mod_sha
51
from bzrlib.symbol_versioning import (
69
63
from bzrlib import symbol_versioning
66
# Cross platform wall-clock time functionality with decent resolution.
67
# On Linux ``time.clock`` returns only CPU time. On Windows, ``time.time()``
68
# only has a resolution of ~15ms. Note that ``time.clock()`` is not
69
# synchronized with ``time.time()``, this is only meant to be used to find
70
# delta times by subtracting from another call to this function.
71
timer_func = time.time
72
if sys.platform == 'win32':
73
timer_func = time.clock
72
75
# On win32, O_BINARY is used to indicate the file should
73
76
# be opened in binary mode, rather than text mode.
74
77
# On other platforms, O_BINARY doesn't exist, because
75
78
# they always open in binary mode, so it is okay to
76
# OR with 0 on those platforms
79
# OR with 0 on those platforms.
80
# O_NOINHERIT and O_TEXT exists only on win32 too.
77
81
O_BINARY = getattr(os, 'O_BINARY', 0)
82
O_TEXT = getattr(os, 'O_TEXT', 0)
83
O_NOINHERIT = getattr(os, 'O_NOINHERIT', 0)
86
def get_unicode_argv():
88
user_encoding = get_user_encoding()
89
return [a.decode(user_encoding) for a in sys.argv[1:]]
90
except UnicodeDecodeError:
91
raise errors.BzrError("Parameter %r encoding is unsupported by %s "
92
"application locale." % (a, user_encoding))
80
95
def make_readonly(filename):
279
331
# /path => C:/path
280
332
path = unicode(path)
281
333
# check for absolute path
282
drive = _nt_splitdrive(path)[0]
334
drive = ntpath.splitdrive(path)[0]
283
335
if drive == '' and path[:2] not in('//','\\\\'):
284
336
cwd = os.getcwdu()
285
337
# we cannot simply os.path.join cwd and path
286
338
# because os.path.join('C:','/path') produce '/path'
287
339
# and this is incorrect
288
340
if path[:1] in ('/','\\'):
289
cwd = _nt_splitdrive(cwd)[0]
341
cwd = ntpath.splitdrive(cwd)[0]
291
343
path = cwd + '\\' + path
292
return _win32_fixdrive(_nt_normpath(path).replace('\\', '/'))
344
return _win32_fixdrive(ntpath.normpath(path).replace('\\', '/'))
295
347
def _win32_realpath(path):
296
# Real _nt_realpath doesn't have a problem with a unicode cwd
297
return _win32_fixdrive(_nt_realpath(unicode(path)).replace('\\', '/'))
348
# Real ntpath.realpath doesn't have a problem with a unicode cwd
349
return _win32_fixdrive(ntpath.realpath(unicode(path)).replace('\\', '/'))
300
352
def _win32_pathjoin(*args):
301
return _nt_join(*args).replace('\\', '/')
353
return ntpath.join(*args).replace('\\', '/')
304
356
def _win32_normpath(path):
305
return _win32_fixdrive(_nt_normpath(unicode(path)).replace('\\', '/'))
357
return _win32_fixdrive(ntpath.normpath(unicode(path)).replace('\\', '/'))
308
360
def _win32_getcwd():
829
954
return pathjoin(*p)
957
def parent_directories(filename):
958
"""Return the list of parent directories, deepest first.
960
For example, parent_directories("a/b/c") -> ["a/b", "a"].
963
parts = splitpath(dirname(filename))
965
parents.append(joinpath(parts))
970
_extension_load_failures = []
973
def failed_to_load_extension(exception):
974
"""Handle failing to load a binary extension.
976
This should be called from the ImportError block guarding the attempt to
977
import the native extension. If this function returns, the pure-Python
978
implementation should be loaded instead::
981
>>> import bzrlib._fictional_extension_pyx
982
>>> except ImportError, e:
983
>>> bzrlib.osutils.failed_to_load_extension(e)
984
>>> import bzrlib._fictional_extension_py
986
# NB: This docstring is just an example, not a doctest, because doctest
987
# currently can't cope with the use of lazy imports in this namespace --
990
# This currently doesn't report the failure at the time it occurs, because
991
# they tend to happen very early in startup when we can't check config
992
# files etc, and also we want to report all failures but not spam the user
994
exception_str = str(exception)
995
if exception_str not in _extension_load_failures:
996
trace.mutter("failed to load compiled extension: %s" % exception_str)
997
_extension_load_failures.append(exception_str)
1000
def report_extension_load_failures():
1001
if not _extension_load_failures:
1003
from bzrlib.config import GlobalConfig
1004
if GlobalConfig().get_user_option_as_bool('ignore_missing_extensions'):
1006
# the warnings framework should by default show this only once
1007
from bzrlib.trace import warning
1009
"bzr: warning: some compiled extensions could not be loaded; "
1010
"see <https://answers.launchpad.net/bzr/+faq/703>")
1011
# we no longer show the specific missing extensions here, because it makes
1012
# the message too long and scary - see
1013
# https://bugs.launchpad.net/bzr/+bug/430529
833
1017
from bzrlib._chunks_to_lines_pyx import chunks_to_lines
1018
except ImportError, e:
1019
failed_to_load_extension(e)
835
1020
from bzrlib._chunks_to_lines_py import chunks_to_lines
875
1060
shutil.copyfile(src, dest)
878
# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
879
# Forgiveness than Permission (EAFP) because:
880
# - root can damage a solaris file system by using unlink,
881
# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
882
# EACCES, OSX: EPERM) when invoked on a directory.
883
1063
def delete_any(path):
884
"""Delete a file or directory."""
1064
"""Delete a file, symlink or directory.
1066
Will delete even if readonly.
1069
_delete_file_or_dir(path)
1070
except (OSError, IOError), e:
1071
if e.errno in (errno.EPERM, errno.EACCES):
1072
# make writable and try again
1075
except (OSError, IOError):
1077
_delete_file_or_dir(path)
1082
def _delete_file_or_dir(path):
1083
# Look Before You Leap (LBYL) is appropriate here instead of Easier to Ask for
1084
# Forgiveness than Permission (EAFP) because:
1085
# - root can damage a solaris file system by using unlink,
1086
# - unlink raises different exceptions on different OSes (linux: EISDIR, win32:
1087
# EACCES, OSX: EPERM) when invoked on a directory.
885
1088
if isdir(path): # Takes care of symlinks
1029
1257
# but for now, we haven't optimized...
1030
1258
return [canonical_relpath(base, p) for p in paths]
1261
def decode_filename(filename):
1262
"""Decode the filename using the filesystem encoding
1264
If it is unicode, it is returned.
1265
Otherwise it is decoded from the the filesystem's encoding. If decoding
1266
fails, a errors.BadFilenameEncoding exception is raised.
1268
if type(filename) is unicode:
1271
return filename.decode(_fs_enc)
1272
except UnicodeDecodeError:
1273
raise errors.BadFilenameEncoding(filename, _fs_enc)
1032
1276
def safe_unicode(unicode_or_utf8_string):
1033
1277
"""Coerce unicode_or_utf8_string into unicode.
1035
1279
If it is unicode, it is returned.
1036
Otherwise it is decoded from utf-8. If a decoding error
1037
occurs, it is wrapped as a If the decoding fails, the exception is wrapped
1038
as a BzrBadParameter exception.
1280
Otherwise it is decoded from utf-8. If decoding fails, the exception is
1281
wrapped in a BzrBadParameterNotUnicode exception.
1040
1283
if isinstance(unicode_or_utf8_string, unicode):
1041
1284
return unicode_or_utf8_string
1154
1397
normalized_filename = _inaccessible_normalized_filename
1400
def set_signal_handler(signum, handler, restart_syscall=True):
1401
"""A wrapper for signal.signal that also calls siginterrupt(signum, False)
1402
on platforms that support that.
1404
:param restart_syscall: if set, allow syscalls interrupted by a signal to
1405
automatically restart (by calling `signal.siginterrupt(signum,
1406
False)`). May be ignored if the feature is not available on this
1407
platform or Python version.
1411
siginterrupt = signal.siginterrupt
1413
# This python implementation doesn't provide signal support, hence no
1416
except AttributeError:
1417
# siginterrupt doesn't exist on this platform, or for this version
1419
siginterrupt = lambda signum, flag: None
1421
def sig_handler(*args):
1422
# Python resets the siginterrupt flag when a signal is
1423
# received. <http://bugs.python.org/issue8354>
1424
# As a workaround for some cases, set it back the way we want it.
1425
siginterrupt(signum, False)
1426
# Now run the handler function passed to set_signal_handler.
1429
sig_handler = handler
1430
old_handler = signal.signal(signum, sig_handler)
1432
siginterrupt(signum, False)
1436
default_terminal_width = 80
1437
"""The default terminal width for ttys.
1439
This is defined so that higher levels can share a common fallback value when
1440
terminal_width() returns None.
1443
# Keep some state so that terminal_width can detect if _terminal_size has
1444
# returned a different size since the process started. See docstring and
1445
# comments of terminal_width for details.
1446
# _terminal_size_state has 3 possible values: no_data, unchanged, and changed.
1447
_terminal_size_state = 'no_data'
1448
_first_terminal_size = None
1157
1450
def terminal_width():
1158
"""Return estimated terminal width."""
1159
if sys.platform == 'win32':
1160
return win32utils.get_console_size()[0]
1451
"""Return terminal width.
1453
None is returned if the width can't established precisely.
1456
- if BZR_COLUMNS is set, returns its value
1457
- if there is no controlling terminal, returns None
1458
- query the OS, if the queried size has changed since the last query,
1460
- if COLUMNS is set, returns its value,
1461
- if the OS has a value (even though it's never changed), return its value.
1463
From there, we need to query the OS to get the size of the controlling
1466
On Unices we query the OS by:
1467
- get termios.TIOCGWINSZ
1468
- if an error occurs or a negative value is obtained, returns None
1470
On Windows we query the OS by:
1471
- win32utils.get_console_size() decides,
1472
- returns None on error (provided default value)
1474
# Note to implementors: if changing the rules for determining the width,
1475
# make sure you've considered the behaviour in these cases:
1476
# - M-x shell in emacs, where $COLUMNS is set and TIOCGWINSZ returns 0,0.
1477
# - bzr log | less, in bash, where $COLUMNS not set and TIOCGWINSZ returns
1479
# - (add more interesting cases here, if you find any)
1480
# Some programs implement "Use $COLUMNS (if set) until SIGWINCH occurs",
1481
# but we don't want to register a signal handler because it is impossible
1482
# to do so without risking EINTR errors in Python <= 2.6.5 (see
1483
# <http://bugs.python.org/issue8354>). Instead we check TIOCGWINSZ every
1484
# time so we can notice if the reported size has changed, which should have
1487
# If BZR_COLUMNS is set, take it, user is always right
1488
# Except if they specified 0 in which case, impose no limit here
1490
width = int(os.environ['BZR_COLUMNS'])
1491
except (KeyError, ValueError):
1493
if width is not None:
1499
isatty = getattr(sys.stdout, 'isatty', None)
1500
if isatty is None or not isatty():
1501
# Don't guess, setting BZR_COLUMNS is the recommended way to override.
1505
width, height = os_size = _terminal_size(None, None)
1506
global _first_terminal_size, _terminal_size_state
1507
if _terminal_size_state == 'no_data':
1508
_first_terminal_size = os_size
1509
_terminal_size_state = 'unchanged'
1510
elif (_terminal_size_state == 'unchanged' and
1511
_first_terminal_size != os_size):
1512
_terminal_size_state = 'changed'
1514
# If the OS claims to know how wide the terminal is, and this value has
1515
# ever changed, use that.
1516
if _terminal_size_state == 'changed':
1517
if width is not None and width > 0:
1520
# If COLUMNS is set, use it.
1522
return int(os.environ['COLUMNS'])
1523
except (KeyError, ValueError):
1526
# Finally, use an unchanged size from the OS, if we have one.
1527
if _terminal_size_state == 'unchanged':
1528
if width is not None and width > 0:
1531
# The width could not be determined.
1535
def _win32_terminal_size(width, height):
1536
width, height = win32utils.get_console_size(defaultx=width, defaulty=height)
1537
return width, height
1540
def _ioctl_terminal_size(width, height):
1163
1542
import struct, fcntl, termios
1164
1543
s = struct.pack('HHHH', 0, 0, 0, 0)
1165
1544
x = fcntl.ioctl(1, termios.TIOCGWINSZ, s)
1166
width = struct.unpack('HHHH', x)[1]
1545
height, width = struct.unpack('HHHH', x)[0:2]
1546
except (IOError, AttributeError):
1171
width = int(os.environ['COLUMNS'])
1548
return width, height
1550
_terminal_size = None
1551
"""Returns the terminal size as (width, height).
1553
:param width: Default value for width.
1554
:param height: Default value for height.
1556
This is defined specifically for each OS and query the size of the controlling
1557
terminal. If any error occurs, the provided default values should be returned.
1559
if sys.platform == 'win32':
1560
_terminal_size = _win32_terminal_size
1562
_terminal_size = _ioctl_terminal_size
1180
1565
def supports_executable():
1604
2019
return socket.gethostname().decode(get_user_encoding())
1607
def recv_all(socket, bytes):
2022
# We must not read/write any more than 64k at a time from/to a socket so we
2023
# don't risk "no buffer space available" errors on some platforms. Windows in
2024
# particular is likely to throw WSAECONNABORTED or WSAENOBUFS if given too much
2026
MAX_SOCKET_CHUNK = 64 * 1024
2028
_end_of_stream_errors = [errno.ECONNRESET]
2029
for _eno in ['WSAECONNRESET', 'WSAECONNABORTED']:
2030
_eno = getattr(errno, _eno, None)
2031
if _eno is not None:
2032
_end_of_stream_errors.append(_eno)
2036
def read_bytes_from_socket(sock, report_activity=None,
2037
max_read_size=MAX_SOCKET_CHUNK):
2038
"""Read up to max_read_size of bytes from sock and notify of progress.
2040
Translates "Connection reset by peer" into file-like EOF (return an
2041
empty string rather than raise an error), and repeats the recv if
2042
interrupted by a signal.
2046
bytes = sock.recv(max_read_size)
2047
except socket.error, e:
2049
if eno in _end_of_stream_errors:
2050
# The connection was closed by the other side. Callers expect
2051
# an empty string to signal end-of-stream.
2053
elif eno == errno.EINTR:
2054
# Retry the interrupted recv.
2058
if report_activity is not None:
2059
report_activity(len(bytes), 'read')
2063
def recv_all(socket, count):
1608
2064
"""Receive an exact number of bytes.
1610
2066
Regular Socket.recv() may return less than the requested number of bytes,
1611
dependning on what's in the OS buffer. MSG_WAITALL is not available
2067
depending on what's in the OS buffer. MSG_WAITALL is not available
1612
2068
on all platforms, but this should work everywhere. This will return
1613
2069
less than the requested amount if the remote end closes.
1615
2071
This isn't optimized and is intended mostly for use in testing.
1618
while len(b) < bytes:
1619
new = until_no_eintr(socket.recv, bytes - len(b))
2074
while len(b) < count:
2075
new = read_bytes_from_socket(socket, None, count - len(b))
1626
def send_all(socket, bytes, report_activity=None):
2082
def send_all(sock, bytes, report_activity=None):
1627
2083
"""Send all bytes on a socket.
1629
Regular socket.sendall() can give socket error 10053 on Windows. This
1630
implementation sends no more than 64k at a time, which avoids this problem.
2085
Breaks large blocks in smaller chunks to avoid buffering limitations on
2086
some platforms, and catches EINTR which may be thrown if the send is
2087
interrupted by a signal.
2089
This is preferred to socket.sendall(), because it avoids portability bugs
2090
and provides activity reporting.
1632
2092
:param report_activity: Call this as bytes are read, see
1633
2093
Transport._report_activity
1636
for pos in xrange(0, len(bytes), chunk_size):
1637
block = bytes[pos:pos+chunk_size]
1638
if report_activity is not None:
1639
report_activity(len(block), 'write')
1640
until_no_eintr(socket.sendall, block)
2096
byte_count = len(bytes)
2097
while sent_total < byte_count:
2099
sent = sock.send(buffer(bytes, sent_total, MAX_SOCKET_CHUNK))
2100
except socket.error, e:
2101
if e.args[0] != errno.EINTR:
2105
report_activity(sent, 'write')
2108
def connect_socket(address):
2109
# Slight variation of the socket.create_connection() function (provided by
2110
# python-2.6) that can fail if getaddrinfo returns an empty list. We also
2111
# provide it for previous python versions. Also, we don't use the timeout
2112
# parameter (provided by the python implementation) so we don't implement
2114
err = socket.error('getaddrinfo returns an empty list')
2115
host, port = address
2116
for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
2117
af, socktype, proto, canonname, sa = res
2120
sock = socket.socket(af, socktype, proto)
2124
except socket.error, err:
2125
# 'err' is now the most recent error
2126
if sock is not None:
1643
2131
def dereference_path(path):
1740
2267
termios.tcsetattr(fd, termios.TCSADRAIN, settings)
2270
if sys.platform == 'linux2':
2271
def _local_concurrency():
2273
return os.sysconf('SC_NPROCESSORS_ONLN')
2274
except (ValueError, OSError, AttributeError):
2276
elif sys.platform == 'darwin':
2277
def _local_concurrency():
2278
return subprocess.Popen(['sysctl', '-n', 'hw.availcpu'],
2279
stdout=subprocess.PIPE).communicate()[0]
2280
elif "bsd" in sys.platform:
2281
def _local_concurrency():
2282
return subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
2283
stdout=subprocess.PIPE).communicate()[0]
2284
elif sys.platform == 'sunos5':
2285
def _local_concurrency():
2286
return subprocess.Popen(['psrinfo', '-p',],
2287
stdout=subprocess.PIPE).communicate()[0]
2288
elif sys.platform == "win32":
2289
def _local_concurrency():
2290
# This appears to return the number of cores.
2291
return os.environ.get('NUMBER_OF_PROCESSORS')
2293
def _local_concurrency():
2298
_cached_local_concurrency = None
2300
def local_concurrency(use_cache=True):
2301
"""Return how many processes can be run concurrently.
2303
Rely on platform specific implementations and default to 1 (one) if
2304
anything goes wrong.
2306
global _cached_local_concurrency
2308
if _cached_local_concurrency is not None and use_cache:
2309
return _cached_local_concurrency
2311
concurrency = os.environ.get('BZR_CONCURRENCY', None)
2312
if concurrency is None:
2314
import multiprocessing
2316
# multiprocessing is only available on Python >= 2.6
2318
concurrency = _local_concurrency()
2319
except (OSError, IOError):
2322
concurrency = multiprocessing.cpu_count()
2324
concurrency = int(concurrency)
2325
except (TypeError, ValueError):
2328
_cached_concurrency = concurrency
2332
class UnicodeOrBytesToBytesWriter(codecs.StreamWriter):
2333
"""A stream writer that doesn't decode str arguments."""
2335
def __init__(self, encode, stream, errors='strict'):
2336
codecs.StreamWriter.__init__(self, stream, errors)
2337
self.encode = encode
2339
def write(self, object):
2340
if type(object) is str:
2341
self.stream.write(object)
2343
data, _ = self.encode(object, self.errors)
2344
self.stream.write(data)
2346
if sys.platform == 'win32':
2347
def open_file(filename, mode='r', bufsize=-1):
2348
"""This function is used to override the ``open`` builtin.
2350
But it uses O_NOINHERIT flag so the file handle is not inherited by
2351
child processes. Deleting or renaming a closed file opened with this
2352
function is not blocking child processes.
2354
writing = 'w' in mode
2355
appending = 'a' in mode
2356
updating = '+' in mode
2357
binary = 'b' in mode
2360
# see http://msdn.microsoft.com/en-us/library/yeby3zcb%28VS.71%29.aspx
2361
# for flags for each modes.
2371
flags |= os.O_WRONLY
2372
flags |= os.O_CREAT | os.O_TRUNC
2377
flags |= os.O_WRONLY
2378
flags |= os.O_CREAT | os.O_APPEND
2383
flags |= os.O_RDONLY
2385
return os.fdopen(os.open(filename, flags), mode, bufsize)
2390
def getuser_unicode():
2391
"""Return the username as unicode.
2394
user_encoding = get_user_encoding()
2395
username = getpass.getuser().decode(user_encoding)
2396
except UnicodeDecodeError:
2397
raise errors.BzrError("Can't decode username as %s." % \
2399
except ImportError, e:
2400
if sys.platform != 'win32':
2402
if str(e) != 'No module named pwd':
2404
# https://bugs.launchpad.net/bzr/+bug/660174
2405
# getpass.getuser() is unable to return username on Windows
2406
# if there is no USERNAME environment variable set.
2407
# That could be true if bzr is running as a service,
2408
# e.g. running `bzr serve` as a service on Windows.
2409
# We should not fail with traceback in this case.
2410
username = u'UNKNOWN'
2414
def available_backup_name(base, exists):
2415
"""Find a non-existing backup file name.
2417
This will *not* create anything, this only return a 'free' entry. This
2418
should be used for checking names in a directory below a locked
2419
tree/branch/repo to avoid race conditions. This is LBYL (Look Before You
2420
Leap) and generally discouraged.
2422
:param base: The base name.
2424
:param exists: A callable returning True if the path parameter exists.
2427
name = "%s.~%d~" % (base, counter)
2430
name = "%s.~%d~" % (base, counter)
2434
def set_fd_cloexec(fd):
2435
"""Set a Unix file descriptor's FD_CLOEXEC flag. Do nothing if platform
2436
support for this is not available.
2440
old = fcntl.fcntl(fd, fcntl.F_GETFD)
2441
fcntl.fcntl(fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
2442
except (ImportError, AttributeError):
2443
# Either the fcntl module or specific constants are not present
2447
def find_executable_on_path(name):
2448
"""Finds an executable on the PATH.
2450
On Windows, this will try to append each extension in the PATHEXT
2451
environment variable to the name, if it cannot be found with the name
2454
:param name: The base name of the executable.
2455
:return: The path to the executable found or None.
2457
path = os.environ.get('PATH')
2460
path = path.split(os.pathsep)
2461
if sys.platform == 'win32':
2462
exts = os.environ.get('PATHEXT', '').split(os.pathsep)
2463
exts = [ext.lower() for ext in exts]
2464
base, ext = os.path.splitext(name)
2466
if ext.lower() not in exts:
2474
f = os.path.join(d, name) + ext
2475
if os.access(f, os.X_OK):
2480
def _posix_is_local_pid_dead(pid):
2481
"""True if pid doesn't correspond to live process on this machine"""
2483
# Special meaning of unix kill: just check if it's there.
2486
if e.errno == errno.ESRCH:
2487
# On this machine, and really not found: as sure as we can be
2490
elif e.errno == errno.EPERM:
2491
# exists, though not ours
2494
mutter("os.kill(%d, 0) failed: %s" % (pid, e))
2495
# Don't really know.
2498
# Exists and our process: not dead.
2501
if sys.platform == "win32":
2502
is_local_pid_dead = win32utils.is_local_pid_dead
2504
is_local_pid_dead = _posix_is_local_pid_dead
2507
def fdatasync(fileno):
2508
"""Flush file contents to disk if possible.
2510
:param fileno: Integer OS file handle.
2511
:raises TransportNotPossible: If flushing to disk is not possible.
2513
fn = getattr(os, 'fdatasync', getattr(os, 'fsync', None))