# © 2022 Nicko van Someren # License: MIT # pylint: disable=missing-module-docstring from ctypes import CDLL, get_errno from os import strerror, PathLike, fsencode from platform import machine from typing import Optional SYSCALL_ARCH_MAP = { 'x86_64': 316, 'armv6l': 382, 'armv7l': 382, 'aarch64': 276, 'i386': 353, } libc = CDLL('libc.so.6', use_errno=True) syscall_function = libc.syscall ARCH = machine() RENAME_EXCHANGE = 2 AT_FDCWD = -100 if ARCH not in SYSCALL_ARCH_MAP: raise NotImplementedError(f'Unsupported architecture: {ARCH}') SYSCALL_RENAMEAT2 = SYSCALL_ARCH_MAP[ARCH] def rename_exchange(oldpath : PathLike, newpath : PathLike, olddirfd : Optional[int] = None, newdirfd : Optional[int] = None) -> None: """Atomically exchange oldpath and newpath. Both pathnames must exist but may be of different types (e.g., one could be a non-empty directory and the other a symbolic link).""" result = syscall_function( SYSCALL_RENAMEAT2, olddirfd if olddirfd is not None else AT_FDCWD, fsencode(oldpath), newdirfd if newdirfd is not None else AT_FDCWD, fsencode(newpath), RENAME_EXCHANGE, ) if result != 0: errno = get_errno() raise OSError(errno, strerror(errno))