osutil: add Libc.futimens() wrapper for futimens() call
Python has no wrapper for a futime*() call so we need to implement it in the `util.linux` package.
This commit is contained in:
parent
ca9f4038c8
commit
f52cabc3c1
2 changed files with 50 additions and 0 deletions
|
|
@ -422,6 +422,14 @@ def fcntl_flock(fd: int, lock_type: int, wait: bool = False):
|
|||
fcntl.fcntl(fd, lock_cmd, arg_flock64)
|
||||
|
||||
|
||||
class c_timespec(ctypes.Structure):
|
||||
_fields_ = [('tv_sec', ctypes.c_long), ('tv_nsec', ctypes.c_long)]
|
||||
|
||||
|
||||
class c_timespec_times2(ctypes.Structure):
|
||||
_fields_ = [('atime', c_timespec), ('mtime', c_timespec)]
|
||||
|
||||
|
||||
class Libc:
|
||||
"""Safe Access to libc
|
||||
|
||||
|
|
@ -434,6 +442,10 @@ class Libc:
|
|||
RENAME_NOREPLACE = ctypes.c_uint(1)
|
||||
RENAME_WHITEOUT = ctypes.c_uint(4)
|
||||
|
||||
# see /usr/include/x86_64-linux-gnu/bits/stat.h
|
||||
UTIME_NOW = ctypes.c_long(((1 << 30) - 1))
|
||||
UTIME_OMIT = ctypes.c_long(((1 << 30) - 2))
|
||||
|
||||
_lock = threading.Lock()
|
||||
_inst = None
|
||||
|
||||
|
|
@ -462,6 +474,22 @@ class Libc:
|
|||
setattr(proto, "errcheck", self._errcheck_errno)
|
||||
setattr(proto, "__name__", "renameat2")
|
||||
self.renameat2 = proto
|
||||
# prototype: futimens
|
||||
proto = ctypes.CFUNCTYPE(
|
||||
ctypes.c_int,
|
||||
ctypes.c_int,
|
||||
ctypes.POINTER(c_timespec_times2),
|
||||
use_errno=True,
|
||||
)(
|
||||
("futimens", self._lib),
|
||||
(
|
||||
(1, "fd"),
|
||||
(1, "timespec"),
|
||||
),
|
||||
)
|
||||
setattr(proto, "errcheck", self._errcheck_errno)
|
||||
setattr(proto, "__name__", "futimens")
|
||||
self.futimens = proto
|
||||
|
||||
@staticmethod
|
||||
def make() -> "Libc":
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
# Tests for the `osbuild.util.linux` module.
|
||||
#
|
||||
|
||||
import ctypes
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
|
@ -240,3 +241,24 @@ def test_proc_boot_id():
|
|||
|
||||
bootid3 = linux.proc_boot_id("foobar")
|
||||
assert bootid.int != bootid3.int
|
||||
|
||||
|
||||
def test_libc_futimens_errcheck():
|
||||
libc = linux.Libc.default()
|
||||
with pytest.raises(OSError):
|
||||
libc.futimens(-1, None)
|
||||
|
||||
|
||||
def test_libc_futimes_works(tmpdir):
|
||||
libc = linux.Libc.default()
|
||||
stamp_file = os.path.join(tmpdir, "foo")
|
||||
with open(stamp_file, "w") as fp:
|
||||
fp.write("meep")
|
||||
mtime1 = os.stat(stamp_file).st_mtime
|
||||
with open(stamp_file, "w") as fp:
|
||||
libc.futimens(fp.fileno(), ctypes.byref(linux.c_timespec_times2(
|
||||
atime=linux.c_timespec(tv_sec=3, tv_nsec=300*1000*1000),
|
||||
mtime=linux.c_timespec(tv_sec=0, tv_nsec=libc.UTIME_OMIT),
|
||||
)))
|
||||
assert os.stat(stamp_file).st_atime == 3.3
|
||||
assert os.stat(stamp_file).st_mtime == mtime1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue