ensure renameat2 checks only run when required
This commit is contained in:
parent
9baea936f2
commit
6bad473e4e
@ -13,18 +13,32 @@
|
|||||||
RENAME_EXCHANGE = 2
|
RENAME_EXCHANGE = 2
|
||||||
AT_FDCWD = -100
|
AT_FDCWD = -100
|
||||||
|
|
||||||
libc: Optional[ctypes.CDLL] = None
|
# object for renameat2 not set
|
||||||
try:
|
# We use None for not found and notset for not set so that boolean checks work
|
||||||
# CDLL(None) returns the python process
|
# properly in client code
|
||||||
# python links against libc, so we can treat this as a libc handle
|
notset = object()
|
||||||
# we could also use CDLL("libc.so.6") but this is (irrelevantly) more future proof
|
_renameat2 = notset
|
||||||
libc = ctypes.CDLL(None)
|
|
||||||
except (OSError, TypeError):
|
|
||||||
# OSError if the call fails,
|
|
||||||
# TypeError on Windows
|
|
||||||
pass
|
|
||||||
|
|
||||||
renameat2 = getattr(libc, "renameat2", None)
|
|
||||||
|
def set_renameat2():
|
||||||
|
libc: Optional[ctypes.CDLL] = None
|
||||||
|
try:
|
||||||
|
# CDLL(None) returns the python process
|
||||||
|
# python links against libc, so we can treat this as a libc handle
|
||||||
|
# we could also use CDLL("libc.so.6") but this is (irrelevantly) more future proof
|
||||||
|
libc = ctypes.CDLL(None)
|
||||||
|
except (OSError, TypeError):
|
||||||
|
# OSError if the call fails,
|
||||||
|
# TypeError on Windows
|
||||||
|
return None
|
||||||
|
|
||||||
|
return getattr(libc, "renameat2", None)
|
||||||
|
|
||||||
|
|
||||||
|
def renameat2():
|
||||||
|
if _renameat2 is notset:
|
||||||
|
_renameat2 = set_renameat2()
|
||||||
|
return _renameat2
|
||||||
|
|
||||||
|
|
||||||
def atomic_update(oldpath, newpath):
|
def atomic_update(oldpath, newpath):
|
||||||
@ -35,7 +49,7 @@ def atomic_update(oldpath, newpath):
|
|||||||
on other systems, oldpath is not affected but all paths are abstracted
|
on other systems, oldpath is not affected but all paths are abstracted
|
||||||
by a symlink to allow for atomic updates.
|
by a symlink to allow for atomic updates.
|
||||||
"""
|
"""
|
||||||
if renameat2:
|
if renameat2():
|
||||||
return atomic_update_renameat2(oldpath, newpath)
|
return atomic_update_renameat2(oldpath, newpath)
|
||||||
else:
|
else:
|
||||||
return atomic_update_symlink(oldpath, newpath)
|
return atomic_update_symlink(oldpath, newpath)
|
||||||
@ -50,7 +64,7 @@ def atomic_update_renameat2(src, dest):
|
|||||||
if not dest_exists:
|
if not dest_exists:
|
||||||
fs.touch(dest)
|
fs.touch(dest)
|
||||||
try:
|
try:
|
||||||
rc = renameat2(AT_FDCWD, src.encode(), AT_FDCWD, dest.encode(), RENAME_EXCHANGE)
|
rc = renameat2()(AT_FDCWD, src.encode(), AT_FDCWD, dest.encode(), RENAME_EXCHANGE)
|
||||||
if rc:
|
if rc:
|
||||||
raise OSError(f"renameat2 failed to exchange {src} and {dest}")
|
raise OSError(f"renameat2 failed to exchange {src} and {dest}")
|
||||||
if not dest_exists:
|
if not dest_exists:
|
||||||
|
Loading…
Reference in New Issue
Block a user