Author: Ronan Lamy <[email protected]>
Branch: follow_symlinks
Changeset: r83304:3869fa0518a7
Date: 2016-03-23 16:53 +0000
http://bitbucket.org/pypy/pypy/changeset/3869fa0518a7/

Log:    Use utimensat() in os.utime() if available

diff --git a/pypy/module/posix/interp_posix.py 
b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -1,5 +1,6 @@
 import os
 import sys
+from math import modf
 
 from rpython.rlib import rposix, rposix_stat
 from rpython.rlib import objectmodel, rurandom
@@ -1137,8 +1138,10 @@
         raise wrap_oserror(space, e)
     return space.wrap(ret)
 
-@unwrap_spec(dir_fd=DirFD(available=False), follow_symlinks=kwonly(bool))
-def utime(space, w_path, w_tuple, dir_fd=DEFAULT_DIR_FD, follow_symlinks=True):
+
+@unwrap_spec(w_ns=kwonly(WrappedDefault(None)),
+    dir_fd=DirFD(rposix.HAVE_UTIMENSAT), follow_symlinks=kwonly(bool))
+def utime(space, w_path, w_times, w_ns, dir_fd=DEFAULT_DIR_FD, 
follow_symlinks=True):
     """utime(path, times=None, *, ns=None, dir_fd=None, follow_symlinks=True)
 
 Set the access and modified time of path.
@@ -1164,7 +1167,28 @@
   as an open file descriptor.
 dir_fd and follow_symlinks may not be available on your platform.
   If they are unavailable, using them will raise a NotImplementedError."""
-    if space.is_w(w_tuple, space.w_None):
+    if (not space.is_w(w_times, space.w_None) and
+            not space.is_w(w_ns, space.w_None)):
+        raise oefmt(space.w_ValueError,
+            "utime: you may specify either 'times' or 'ns' but not both")
+
+    if rposix.HAVE_UTIMENSAT:
+        path = space.fsencode_w(w_path)
+        try:
+            _utimensat(space, path, w_times, w_ns, dir_fd, follow_symlinks)
+            return
+        except OSError, e:
+            raise wrap_oserror2(space, e, w_path)
+
+    if not follow_symlinks:
+        raise oefmt(
+            space.w_NotImplementedError,
+            "follow_symlinks unavailable on this platform")
+
+    if not space.is_w(w_ns, space.w_None):
+        raise oefmt(space.w_NotImplementedError,
+            "utime: 'ns' unsupported on this platform on PyPy")
+    if space.is_w(w_times, space.w_None):
         try:
             dispatch_filename(rposix.utime, 1)(space, w_path, None)
             return
@@ -1172,7 +1196,7 @@
             raise wrap_oserror2(space, e, w_path)
     try:
         msg = "utime() arg 2 must be a tuple (atime, mtime) or None"
-        args_w = space.fixedview(w_tuple)
+        args_w = space.fixedview(w_times)
         if len(args_w) != 2:
             raise OperationError(space.w_TypeError, space.wrap(msg))
         actime = space.float_w(args_w[0], allow_conversion=False)
@@ -1185,6 +1209,51 @@
             raise
         raise OperationError(space.w_TypeError, space.wrap(msg))
 
+
+def _utimensat(space, path, w_times, w_ns, dir_fd, follow_symlinks):
+    if space.is_w(w_times, space.w_None) and space.is_w(w_ns, space.w_None):
+        atime_s = mtime_s = 0
+        atime_ns = mtime_ns = rposix.UTIME_NOW
+    elif not space.is_w(w_times, space.w_None):
+        times_w = space.fixedview(w_times)
+        if len(times_w) != 2:
+            raise oefmt(space.w_TypeError,
+                "utime: 'ns' must be a tuple of two ints")
+        atime_s, atime_ns = convert_seconds(space, times_w[0])
+        mtime_s, mtime_ns = convert_seconds(space, times_w[1])
+    else:
+        args_w = space.fixedview(w_ns)
+        if len(args_w) != 2:
+            raise oefmt(space.w_TypeError,
+                "utime: 'ns' must be a tuple of two ints")
+        atime_s, atime_ns = convert_ns(space, args_w[0])
+        mtime_s, mtime_ns = convert_ns(space, args_w[1])
+
+    rposix.utimensat(
+        path, atime_s, atime_ns, mtime_s, mtime_ns,
+        dir_fd=dir_fd, follow_symlinks=follow_symlinks)
+
+def convert_seconds(space, w_time):
+    if space.isinstance_w(w_time, space.w_float):
+        time = space.float_w(w_time)
+        intpart, floatpart = modf(time)
+        if floatpart < 0:
+            floatpart += 1.
+            intpart -= 1.
+        return int(intpart), int(floatpart*1e9)
+    else:
+        time = space.int_w(w_time)
+        return time, 0
+
+def convert_ns(space, w_ns_time):
+    w_billion = space.wrap(1000000000)
+    w_res = space.divmod(w_ns_time, w_billion)
+    res_w = space.fixedview(w_res)
+    time_int = space.int_w(res_w[0])
+    time_frac = space.int_w(res_w[1])
+    return time_int, time_frac
+
+
 def uname(space):
     """ uname() -> (sysname, nodename, release, version, machine)
 
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to