mirror of
https://github.com/python/cpython.git
synced 2025-08-28 04:35:02 +00:00
Issue #14127: Add ns= parameter to utime, futimes, and lutimes.
Removed futimens as it is now redundant. Changed shutil.copystat to use st_atime_ns and st_mtime_ns from os.stat and ns= parameter to utime--it once again preserves exact metadata on Linux!
This commit is contained in:
parent
3a7f7977f1
commit
76ad59b7e8
6 changed files with 346 additions and 237 deletions
|
@ -934,13 +934,11 @@ as internal buffering of data.
|
||||||
.. versionadded:: 3.3
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
.. function:: futimes(fd[, times])
|
.. function:: futimes(fd[, times, *, ns=times])
|
||||||
|
|
||||||
Set the access and modified time of the file specified by the file
|
Set the access and modified time of the file specified by the file
|
||||||
descriptor *fd* to the given values. *atimes* must be a 2-tuple of numbers,
|
descriptor *fd* to the given values. See :func:`utime` for proper
|
||||||
of the form ``(atime, mtime)``, or None. If no second argument is used,
|
use of the *times* and *ns* arguments.
|
||||||
set the access and modified times to the current time.
|
|
||||||
|
|
||||||
Availability: Unix.
|
Availability: Unix.
|
||||||
|
|
||||||
.. versionadded:: 3.3
|
.. versionadded:: 3.3
|
||||||
|
@ -1762,12 +1760,11 @@ Files and Directories
|
||||||
Added support for Windows 6.0 (Vista) symbolic links.
|
Added support for Windows 6.0 (Vista) symbolic links.
|
||||||
|
|
||||||
|
|
||||||
.. function:: lutimes(path[, times])
|
.. function:: lutimes(path[, times, *, ns=times])
|
||||||
|
|
||||||
Like :func:`utime`, but if *path* is a symbolic link, it is not
|
Like :func:`utime`, but if *path* is a symbolic link, it is not
|
||||||
dereferenced. *times* must be a 2-tuple of numbers, of the form
|
dereferenced. See :func:`utime` for proper use of the
|
||||||
``(atime, mtime)``, or None.
|
*times* and *ns* arguments.
|
||||||
|
|
||||||
|
|
||||||
Availability: Unix.
|
Availability: Unix.
|
||||||
|
|
||||||
|
@ -2226,22 +2223,43 @@ Files and Directories
|
||||||
Availability: Unix, Windows.
|
Availability: Unix, Windows.
|
||||||
|
|
||||||
|
|
||||||
.. function:: utime(path[, times])
|
.. function:: utime(path[, times, *, ns=(atime_ns, mtime_ns)])
|
||||||
|
|
||||||
Set the access and modified times of the file specified by *path*. If *times*
|
Set the access and modified times of the file specified by *path*.
|
||||||
is ``None`` or not specified, then the file's access and modified times are
|
|
||||||
set to the current time. (The effect is similar to running the Unix program
|
:func:`utime` takes two optional parameters, *times* and *ns*.
|
||||||
:program:`touch` on the path.) Otherwise, *times* must be a 2-tuple of
|
These specify the times set on *path* and are used as follows:
|
||||||
numbers, of the form ``(atime, mtime)`` which is used to set the access and
|
|
||||||
modified times, respectively. Whether a directory can be given for *path*
|
- If *ns* is specified,
|
||||||
|
it must be a 2-tuple of the form ``(atime_ns, mtime_ns)``
|
||||||
|
where each member is an int expressing nanoseconds.
|
||||||
|
- If *times* is specified and is not ``None``,
|
||||||
|
it must be a 2-tuple of the form ``(atime, mtime)``
|
||||||
|
where each member is an int or float expressing seconds.
|
||||||
|
- If *times* is specified as ``None``,
|
||||||
|
this is equivalent to specifying an ``(atime, mtime)``
|
||||||
|
where both times are the current time.
|
||||||
|
(The effect is similar to running the Unix program
|
||||||
|
:program:`touch` on *path*.)
|
||||||
|
- If neither *ns* nor *times* is specified, this is
|
||||||
|
equivalent to specifying *times* as ``None``.
|
||||||
|
|
||||||
|
Specifying both *times* and *ns* simultaneously is an error.
|
||||||
|
|
||||||
|
Whether a directory can be given for *path*
|
||||||
depends on whether the operating system implements directories as files
|
depends on whether the operating system implements directories as files
|
||||||
(for example, Windows does not). Note that the exact times you set here may
|
(for example, Windows does not). Note that the exact times you set here may
|
||||||
not be returned by a subsequent :func:`~os.stat` call, depending on the
|
not be returned by a subsequent :func:`~os.stat` call, depending on the
|
||||||
resolution with which your operating system records access and modification
|
resolution with which your operating system records access and modification
|
||||||
times; see :func:`~os.stat`.
|
times; see :func:`~os.stat`. The best way to preserve exact times is to
|
||||||
|
use the *st_atime_ns* and *st_mtime_ns* fields from the :func:`os.stat`
|
||||||
|
result object with the *ns* parameter to `utime`.
|
||||||
|
|
||||||
Availability: Unix, Windows.
|
Availability: Unix, Windows.
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
The :attr:`ns` keyword parameter.
|
||||||
|
|
||||||
|
|
||||||
.. function:: walk(top, topdown=True, onerror=None, followlinks=False)
|
.. function:: walk(top, topdown=True, onerror=None, followlinks=False)
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,10 @@ PyAPI_FUNC(int) _PyTime_ObjectToTime_t(
|
||||||
PyAPI_FUNC(PyObject *) _PyLong_FromTime_t(
|
PyAPI_FUNC(PyObject *) _PyLong_FromTime_t(
|
||||||
time_t sec);
|
time_t sec);
|
||||||
|
|
||||||
|
/* Convert a PyLong to a time_t. */
|
||||||
|
PyAPI_FUNC(time_t) _PyLong_AsTime_t(
|
||||||
|
PyObject *obj);
|
||||||
|
|
||||||
/* Convert a number of seconds, int or float, to a timeval structure.
|
/* Convert a number of seconds, int or float, to a timeval structure.
|
||||||
usec is in the range [0; 999999] and rounded towards zero.
|
usec is in the range [0; 999999] and rounded towards zero.
|
||||||
For example, -1.2 is converted to (-2, 800000). */
|
For example, -1.2 is converted to (-2, 800000). */
|
||||||
|
|
|
@ -154,7 +154,7 @@ def copystat(src, dst, symlinks=False):
|
||||||
|
|
||||||
st = stat_func(src)
|
st = stat_func(src)
|
||||||
mode = stat.S_IMODE(st.st_mode)
|
mode = stat.S_IMODE(st.st_mode)
|
||||||
utime_func(dst, (st.st_atime, st.st_mtime))
|
utime_func(dst, ns=(st.st_atime_ns, st.st_mtime_ns))
|
||||||
chmod_func(dst, mode)
|
chmod_func(dst, mode)
|
||||||
if hasattr(st, 'st_flags'):
|
if hasattr(st, 'st_flags'):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -192,11 +192,11 @@ class StatAttributeTests(unittest.TestCase):
|
||||||
self.assertIn(attr, members)
|
self.assertIn(attr, members)
|
||||||
|
|
||||||
# Make sure that the st_?time and st_?time_ns fields roughly agree
|
# Make sure that the st_?time and st_?time_ns fields roughly agree
|
||||||
# (they should always agree up to the tens-of-microseconds magnitude)
|
# (they should always agree up to around tens-of-microseconds)
|
||||||
for name in 'st_atime st_mtime st_ctime'.split():
|
for name in 'st_atime st_mtime st_ctime'.split():
|
||||||
floaty = int(getattr(result, name) * 100000)
|
floaty = int(getattr(result, name) * 100000)
|
||||||
nanosecondy = getattr(result, name + "_ns") // 10000
|
nanosecondy = getattr(result, name + "_ns") // 10000
|
||||||
self.assertEqual(floaty, nanosecondy)
|
self.assertAlmostEqual(floaty, nanosecondy, delta=2)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result[200]
|
result[200]
|
||||||
|
@ -303,20 +303,80 @@ class StatAttributeTests(unittest.TestCase):
|
||||||
st2 = os.stat(support.TESTFN)
|
st2 = os.stat(support.TESTFN)
|
||||||
self.assertEqual(st2.st_mtime, int(st.st_mtime-delta))
|
self.assertEqual(st2.st_mtime, int(st.st_mtime-delta))
|
||||||
|
|
||||||
def test_utime_noargs(self):
|
def _test_utime(self, filename, attr, utime, delta):
|
||||||
# Issue #13327 removed the requirement to pass None as the
|
# Issue #13327 removed the requirement to pass None as the
|
||||||
# second argument. Check that the previous methods of passing
|
# second argument. Check that the previous methods of passing
|
||||||
# a time tuple or None work in addition to no argument.
|
# a time tuple or None work in addition to no argument.
|
||||||
st = os.stat(support.TESTFN)
|
st0 = os.stat(filename)
|
||||||
# Doesn't set anything new, but sets the time tuple way
|
# Doesn't set anything new, but sets the time tuple way
|
||||||
os.utime(support.TESTFN, (st.st_atime, st.st_mtime))
|
utime(filename, (attr(st0, "st_atime"), attr(st0, "st_mtime")))
|
||||||
|
# Setting the time to the time you just read, then reading again,
|
||||||
|
# should always return exactly the same times.
|
||||||
|
st1 = os.stat(filename)
|
||||||
|
self.assertEqual(attr(st0, "st_mtime"), attr(st1, "st_mtime"))
|
||||||
|
self.assertEqual(attr(st0, "st_atime"), attr(st1, "st_atime"))
|
||||||
# Set to the current time in the old explicit way.
|
# Set to the current time in the old explicit way.
|
||||||
os.utime(support.TESTFN, None)
|
os.utime(filename, None)
|
||||||
st1 = os.stat(support.TESTFN)
|
|
||||||
# Set to the current time in the new way
|
|
||||||
os.utime(support.TESTFN)
|
|
||||||
st2 = os.stat(support.TESTFN)
|
st2 = os.stat(support.TESTFN)
|
||||||
self.assertAlmostEqual(st1.st_mtime, st2.st_mtime, delta=10)
|
# Set to the current time in the new way
|
||||||
|
os.utime(filename)
|
||||||
|
st3 = os.stat(filename)
|
||||||
|
self.assertAlmostEqual(attr(st2, "st_mtime"), attr(st3, "st_mtime"), delta=delta)
|
||||||
|
|
||||||
|
def test_utime(self):
|
||||||
|
def utime(file, times):
|
||||||
|
return os.utime(file, times)
|
||||||
|
self._test_utime(self.fname, getattr, utime, 10)
|
||||||
|
self._test_utime(support.TESTFN, getattr, utime, 10)
|
||||||
|
|
||||||
|
|
||||||
|
def _test_utime_ns(self, set_times_ns, test_dir=True):
|
||||||
|
def getattr_ns(o, attr):
|
||||||
|
return getattr(o, attr + "_ns")
|
||||||
|
ten_s = 10 * 1000 * 1000 * 1000
|
||||||
|
self._test_utime(self.fname, getattr_ns, set_times_ns, ten_s)
|
||||||
|
if test_dir:
|
||||||
|
self._test_utime(support.TESTFN, getattr_ns, set_times_ns, ten_s)
|
||||||
|
|
||||||
|
def test_utime_ns(self):
|
||||||
|
def utime_ns(file, times):
|
||||||
|
return os.utime(file, ns=times)
|
||||||
|
self._test_utime_ns(utime_ns)
|
||||||
|
|
||||||
|
requires_lutimes = unittest.skipUnless(hasattr(os, 'lutimes'),
|
||||||
|
"os.lutimes required for this test.")
|
||||||
|
requires_futimes = unittest.skipUnless(hasattr(os, 'futimes'),
|
||||||
|
"os.futimes required for this test.")
|
||||||
|
|
||||||
|
@requires_lutimes
|
||||||
|
def test_lutimes_ns(self):
|
||||||
|
def lutimes_ns(file, times):
|
||||||
|
return os.lutimes(file, ns=times)
|
||||||
|
self._test_utime_ns(lutimes_ns)
|
||||||
|
|
||||||
|
@requires_futimes
|
||||||
|
def test_futimes_ns(self):
|
||||||
|
def futimes_ns(file, times):
|
||||||
|
with open(file, "wb") as f:
|
||||||
|
os.futimes(f.fileno(), ns=times)
|
||||||
|
self._test_utime_ns(futimes_ns, test_dir=False)
|
||||||
|
|
||||||
|
def _utime_invalid_arguments(self, name, arg):
|
||||||
|
with self.assertRaises(RuntimeError):
|
||||||
|
getattr(os, name)(arg, (5, 5), ns=(5, 5))
|
||||||
|
|
||||||
|
def test_utime_invalid_arguments(self):
|
||||||
|
self._utime_invalid_arguments('utime', self.fname)
|
||||||
|
|
||||||
|
@requires_lutimes
|
||||||
|
def test_lutimes_invalid_arguments(self):
|
||||||
|
self._utime_invalid_arguments('lutimes', self.fname)
|
||||||
|
|
||||||
|
@requires_futimes
|
||||||
|
def test_futimes_invalid_arguments(self):
|
||||||
|
with open(self.fname, "wb") as f:
|
||||||
|
self._utime_invalid_arguments('futimes', f.fileno())
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(stat_supports_subsecond,
|
@unittest.skipUnless(stat_supports_subsecond,
|
||||||
"os.stat() doesn't has a subsecond resolution")
|
"os.stat() doesn't has a subsecond resolution")
|
||||||
|
@ -338,8 +398,7 @@ class StatAttributeTests(unittest.TestCase):
|
||||||
os.utime(filename, (atime, mtime))
|
os.utime(filename, (atime, mtime))
|
||||||
self._test_utime_subsecond(set_time)
|
self._test_utime_subsecond(set_time)
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(os, 'futimes'),
|
@requires_futimes
|
||||||
"os.futimes required for this test.")
|
|
||||||
def test_futimes_subsecond(self):
|
def test_futimes_subsecond(self):
|
||||||
def set_time(filename, atime, mtime):
|
def set_time(filename, atime, mtime):
|
||||||
with open(filename, "wb") as f:
|
with open(filename, "wb") as f:
|
||||||
|
@ -375,8 +434,7 @@ class StatAttributeTests(unittest.TestCase):
|
||||||
os.close(dirfd)
|
os.close(dirfd)
|
||||||
self._test_utime_subsecond(set_time)
|
self._test_utime_subsecond(set_time)
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(os, 'lutimes'),
|
@requires_lutimes
|
||||||
"os.lutimes required for this test.")
|
|
||||||
def test_lutimes_subsecond(self):
|
def test_lutimes_subsecond(self):
|
||||||
def set_time(filename, atime, mtime):
|
def set_time(filename, atime, mtime):
|
||||||
os.lutimes(filename, (atime, mtime))
|
os.lutimes(filename, (atime, mtime))
|
||||||
|
|
|
@ -3572,28 +3572,194 @@ posix_uname(PyObject *self, PyObject *noargs)
|
||||||
#endif /* HAVE_UNAME */
|
#endif /* HAVE_UNAME */
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
split_py_long_to_s_and_ns(PyObject *py_long, time_t *s, long *ns)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
PyObject *divmod;
|
||||||
|
divmod = PyNumber_Divmod(py_long, billion);
|
||||||
|
if (!divmod)
|
||||||
|
goto exit;
|
||||||
|
*s = _PyLong_AsTime_t(PyTuple_GET_ITEM(divmod, 0));
|
||||||
|
if ((*s == -1) && PyErr_Occurred())
|
||||||
|
goto exit;
|
||||||
|
*ns = PyLong_AsLong(PyTuple_GET_ITEM(divmod, 1));
|
||||||
|
if ((*s == -1) && PyErr_Occurred())
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
result = 1;
|
||||||
|
exit:
|
||||||
|
Py_XDECREF(divmod);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef int (*parameter_converter_t)(PyObject *, void *);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* input only */
|
||||||
|
char path_format;
|
||||||
|
parameter_converter_t converter;
|
||||||
|
char *function_name;
|
||||||
|
char *first_argument_name;
|
||||||
|
PyObject *args;
|
||||||
|
PyObject *kwargs;
|
||||||
|
|
||||||
|
/* input/output */
|
||||||
|
PyObject **path;
|
||||||
|
|
||||||
|
/* output only */
|
||||||
|
int now;
|
||||||
|
time_t atime_s;
|
||||||
|
long atime_ns;
|
||||||
|
time_t mtime_s;
|
||||||
|
long mtime_ns;
|
||||||
|
} utime_arguments;
|
||||||
|
|
||||||
|
#define DECLARE_UA(ua, fname) \
|
||||||
|
utime_arguments ua; \
|
||||||
|
memset(&ua, 0, sizeof(ua)); \
|
||||||
|
ua.function_name = fname; \
|
||||||
|
ua.args = args; \
|
||||||
|
ua.kwargs = kwargs; \
|
||||||
|
ua.first_argument_name = "path"; \
|
||||||
|
|
||||||
|
/* UA_TO_FILETIME doesn't declare atime and mtime for you */
|
||||||
|
#define UA_TO_FILETIME(ua, atime, mtime) \
|
||||||
|
time_t_to_FILE_TIME(ua.atime_s, ua.atime_ns, &atime); \
|
||||||
|
time_t_to_FILE_TIME(ua.mtime_s, ua.mtime_ns, &mtime)
|
||||||
|
|
||||||
|
/* the rest of these macros declare the output variable for you */
|
||||||
|
#define UA_TO_TIMESPEC(ua, ts) \
|
||||||
|
struct timespec ts[2]; \
|
||||||
|
ts[0].tv_sec = ua.atime_s; \
|
||||||
|
ts[0].tv_nsec = ua.atime_ns; \
|
||||||
|
ts[1].tv_sec = ua.mtime_s; \
|
||||||
|
ts[1].tv_nsec = ua.mtime_ns
|
||||||
|
|
||||||
|
#define UA_TO_TIMEVAL(ua, tv) \
|
||||||
|
struct timeval tv[2]; \
|
||||||
|
tv[0].tv_sec = ua.atime_s; \
|
||||||
|
tv[0].tv_usec = ua.atime_ns / 1000; \
|
||||||
|
tv[1].tv_sec = ua.mtime_s; \
|
||||||
|
tv[1].tv_usec = ua.mtime_ns / 1000
|
||||||
|
|
||||||
|
#define UA_TO_UTIMBUF(ua, u) \
|
||||||
|
struct utimbuf u; \
|
||||||
|
utimbuf.actime = ua.atime_s; \
|
||||||
|
utimbuf.modtime = ua.mtime_s
|
||||||
|
|
||||||
|
#define UA_TO_TIME_T(ua, timet) \
|
||||||
|
time_t timet[2]; \
|
||||||
|
timet[0] = ua.atime_s; \
|
||||||
|
timet[1] = ua.mtime_s
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* utime_read_time_arguments() processes arguments for the utime
|
||||||
|
* family of functions.
|
||||||
|
* returns zero on failure.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
utime_read_time_arguments(utime_arguments *ua)
|
||||||
|
{
|
||||||
|
PyObject *times = NULL;
|
||||||
|
PyObject *ns = NULL;
|
||||||
|
char format[24];
|
||||||
|
char *kwlist[4];
|
||||||
|
char **kw = kwlist;
|
||||||
|
int return_value;
|
||||||
|
|
||||||
|
*kw++ = ua->first_argument_name;
|
||||||
|
*kw++ = "times";
|
||||||
|
*kw++ = "ns";
|
||||||
|
*kw = NULL;
|
||||||
|
|
||||||
|
sprintf(format, "%c%s|O$O:%s",
|
||||||
|
ua->path_format,
|
||||||
|
ua->converter ? "&" : "",
|
||||||
|
ua->function_name);
|
||||||
|
|
||||||
|
if (ua->converter)
|
||||||
|
return_value = PyArg_ParseTupleAndKeywords(ua->args, ua->kwargs,
|
||||||
|
format, kwlist, ua->converter, ua->path, ×, &ns);
|
||||||
|
else
|
||||||
|
return_value = PyArg_ParseTupleAndKeywords(ua->args, ua->kwargs,
|
||||||
|
format, kwlist, ua->path, ×, &ns);
|
||||||
|
|
||||||
|
if (!return_value)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (times && ns) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError,
|
||||||
|
"%s: you may specify either 'times'"
|
||||||
|
" or 'ns' but not both",
|
||||||
|
ua->function_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (times && (times != Py_None)) {
|
||||||
|
if (!PyTuple_CheckExact(times) || (PyTuple_Size(times) != 2)) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"%s: 'time' must be either"
|
||||||
|
" a valid tuple of two ints or None",
|
||||||
|
ua->function_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ua->now = 0;
|
||||||
|
return (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 0),
|
||||||
|
&(ua->atime_s), &(ua->atime_ns)) != -1)
|
||||||
|
&& (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 1),
|
||||||
|
&(ua->mtime_s), &(ua->mtime_ns)) != -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ns) {
|
||||||
|
if (!PyTuple_CheckExact(ns) || (PyTuple_Size(ns) != 2)) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"%s: 'ns' must be a valid tuple of two ints",
|
||||||
|
ua->function_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ua->now = 0;
|
||||||
|
return (split_py_long_to_s_and_ns(PyTuple_GET_ITEM(ns, 0),
|
||||||
|
&(ua->atime_s), &(ua->atime_ns)))
|
||||||
|
&& (split_py_long_to_s_and_ns(PyTuple_GET_ITEM(ns, 1),
|
||||||
|
&(ua->mtime_s), &(ua->mtime_ns)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* either times=None, or neither times nor ns was specified. use "now". */
|
||||||
|
ua->now = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(posix_utime__doc__,
|
PyDoc_STRVAR(posix_utime__doc__,
|
||||||
"utime(path[, (atime, mtime)])\n\
|
"utime(path[, times=(atime, mtime), *, ns=(atime_ns, mtime_ns)])\n\
|
||||||
Set the access and modified time of the file to the given values.\n\
|
Set the access and modified time of the file.\n\
|
||||||
If no second argument is used, set the access and modified times to\n\
|
If the second argument ('times') is specified,\n\
|
||||||
the current time.");
|
the values should be expressed as float seconds since the epoch.\n\
|
||||||
|
If the keyword argument 'ns' is specified,\n\
|
||||||
|
the values should be expressed as integer nanoseconds since the epoch.\n\
|
||||||
|
If neither the second nor the 'ns' argument is specified,\n\
|
||||||
|
utime uses the current time.\n\
|
||||||
|
Specifying both 'times' and 'ns' is an error.");
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
posix_utime(PyObject *self, PyObject *args)
|
posix_utime(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
PyObject *arg = Py_None;
|
PyObject *upath;
|
||||||
PyObject *obwpath;
|
|
||||||
wchar_t *wpath = NULL;
|
|
||||||
const char *apath;
|
|
||||||
HANDLE hFile;
|
HANDLE hFile;
|
||||||
time_t atimesec, mtimesec;
|
|
||||||
long ansec, mnsec;
|
|
||||||
FILETIME atime, mtime;
|
|
||||||
PyObject *result = NULL;
|
PyObject *result = NULL;
|
||||||
|
FILETIME atime, mtime;
|
||||||
|
|
||||||
if (PyArg_ParseTuple(args, "U|O:utime", &obwpath, &arg)) {
|
DECLARE_UA(ua, "utime");
|
||||||
wpath = PyUnicode_AsUnicode(obwpath);
|
|
||||||
|
ua.path_format = 'U';
|
||||||
|
ua.path = &upath;
|
||||||
|
|
||||||
|
if (!utime_read_time_arguments(&ua)) {
|
||||||
|
wchar_t *wpath = PyUnicode_AsUnicode(upath);
|
||||||
if (wpath == NULL)
|
if (wpath == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
@ -3602,14 +3768,17 @@ posix_utime(PyObject *self, PyObject *args)
|
||||||
FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
if (hFile == INVALID_HANDLE_VALUE)
|
if (hFile == INVALID_HANDLE_VALUE)
|
||||||
return win32_error_object("utime", obwpath);
|
return win32_error_object("utime", upath);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
const char *apath;
|
||||||
/* Drop the argument parsing error as narrow strings
|
/* Drop the argument parsing error as narrow strings
|
||||||
are also valid. */
|
are also valid. */
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "y|O:utime", &apath, &arg))
|
ua.path_format = 'y';
|
||||||
|
ua.path = (PyObject **)&apath;
|
||||||
|
if (!utime_read_time_arguments(&ua))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (win32_warn_bytes_api())
|
if (win32_warn_bytes_api())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -3625,7 +3794,7 @@ posix_utime(PyObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg == Py_None) {
|
if (ua.now) {
|
||||||
SYSTEMTIME now;
|
SYSTEMTIME now;
|
||||||
GetSystemTime(&now);
|
GetSystemTime(&now);
|
||||||
if (!SystemTimeToFileTime(&now, &mtime) ||
|
if (!SystemTimeToFileTime(&now, &mtime) ||
|
||||||
|
@ -3634,20 +3803,8 @@ posix_utime(PyObject *self, PyObject *args)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"utime() arg 2 must be a tuple (atime, mtime)");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 0),
|
UA_TO_FILETIME(ua, atime, mtime);
|
||||||
&atimesec, &ansec) == -1)
|
|
||||||
goto done;
|
|
||||||
time_t_to_FILE_TIME(atimesec, ansec, &atime);
|
|
||||||
if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 1),
|
|
||||||
&mtimesec, &mnsec) == -1)
|
|
||||||
goto done;
|
|
||||||
time_t_to_FILE_TIME(mtimesec, mnsec, &mtime);
|
|
||||||
}
|
}
|
||||||
if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
|
if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
|
||||||
/* Avoid putting the file name into the error here,
|
/* Avoid putting the file name into the error here,
|
||||||
|
@ -3663,136 +3820,85 @@ done:
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
return result;
|
return result;
|
||||||
#else /* MS_WINDOWS */
|
#else /* MS_WINDOWS */
|
||||||
|
|
||||||
PyObject *opath;
|
PyObject *opath;
|
||||||
char *path;
|
char *path;
|
||||||
time_t atime, mtime;
|
|
||||||
long ansec, mnsec;
|
|
||||||
int res;
|
int res;
|
||||||
PyObject* arg = Py_None;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O&|O:utime",
|
DECLARE_UA(ua, "utime");
|
||||||
PyUnicode_FSConverter, &opath, &arg))
|
|
||||||
|
ua.path_format = 'O';
|
||||||
|
ua.path = &opath;
|
||||||
|
ua.converter = PyUnicode_FSConverter;
|
||||||
|
|
||||||
|
if (!utime_read_time_arguments(&ua))
|
||||||
return NULL;
|
return NULL;
|
||||||
path = PyBytes_AsString(opath);
|
path = PyBytes_AsString(opath);
|
||||||
if (arg == Py_None) {
|
if (ua.now) {
|
||||||
/* optional time values not given */
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
res = utime(path, NULL);
|
res = utime(path, NULL);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
}
|
}
|
||||||
else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"utime() arg 2 must be a tuple (atime, mtime)");
|
|
||||||
Py_DECREF(opath);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 0),
|
|
||||||
&atime, &ansec) == -1) {
|
|
||||||
Py_DECREF(opath);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 1),
|
|
||||||
&mtime, &mnsec) == -1) {
|
|
||||||
Py_DECREF(opath);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
{
|
|
||||||
#ifdef HAVE_UTIMENSAT
|
#ifdef HAVE_UTIMENSAT
|
||||||
struct timespec buf[2];
|
UA_TO_TIMESPEC(ua, buf);
|
||||||
buf[0].tv_sec = atime;
|
|
||||||
buf[0].tv_nsec = ansec;
|
|
||||||
buf[1].tv_sec = mtime;
|
|
||||||
buf[1].tv_nsec = mnsec;
|
|
||||||
res = utimensat(AT_FDCWD, path, buf, 0);
|
res = utimensat(AT_FDCWD, path, buf, 0);
|
||||||
#elif defined(HAVE_UTIMES)
|
#elif defined(HAVE_UTIMES)
|
||||||
struct timeval buf[2];
|
UA_TO_TIMEVAL(ua, buf);
|
||||||
buf[0].tv_sec = atime;
|
|
||||||
buf[0].tv_usec = ansec / 1000;
|
|
||||||
buf[1].tv_sec = mtime;
|
|
||||||
buf[1].tv_usec = mnsec / 1000;
|
|
||||||
res = utimes(path, buf);
|
res = utimes(path, buf);
|
||||||
#elif defined(HAVE_UTIME_H)
|
#elif defined(HAVE_UTIME_H)
|
||||||
/* XXX should define struct utimbuf instead, above */
|
/* XXX should define struct utimbuf instead, above */
|
||||||
struct utimbuf buf;
|
UA_TO_UTIMBUF(ua, buf);
|
||||||
buf.actime = atime;
|
|
||||||
buf.modtime = mtime;
|
|
||||||
res = utime(path, &buf);
|
res = utime(path, &buf);
|
||||||
#else
|
#else
|
||||||
time_t buf[2];
|
UA_TO_TIME_T(ua, buf);
|
||||||
buf[0] = atime;
|
|
||||||
buf[1] = mtime;
|
|
||||||
res = utime(path, buf);
|
res = utime(path, buf);
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
return posix_error_with_allocated_filename(opath);
|
return posix_error_with_allocated_filename(opath);
|
||||||
}
|
}
|
||||||
Py_DECREF(opath);
|
Py_DECREF(opath);
|
||||||
Py_INCREF(Py_None);
|
Py_RETURN_NONE;
|
||||||
return Py_None;
|
|
||||||
#undef UTIME_EXTRACT
|
#undef UTIME_EXTRACT
|
||||||
#endif /* MS_WINDOWS */
|
#endif /* MS_WINDOWS */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_FUTIMES
|
#ifdef HAVE_FUTIMES
|
||||||
PyDoc_STRVAR(posix_futimes__doc__,
|
PyDoc_STRVAR(posix_futimes__doc__,
|
||||||
"futimes(fd[, (atime, mtime)])\n\
|
"futimes(fd[, times=(atime, mtime), *, ns=(atime_ns, mtime_ns)])\n\
|
||||||
Set the access and modified time of the file specified by the file\n\
|
Set the access and modified time of the file specified by the file\n\
|
||||||
descriptor fd to the given values. If no second argument is used, set the\n\
|
descriptor fd. See utime for the semantics of the times and ns parameters.");
|
||||||
access and modified times to the current time.");
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
posix_futimes(PyObject *self, PyObject *args)
|
posix_futimes(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
int res, fd;
|
int res, fd;
|
||||||
PyObject* arg = Py_None;
|
|
||||||
time_t atime, mtime;
|
|
||||||
long ansec, mnsec;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i|O:futimes", &fd, &arg))
|
DECLARE_UA(ua, "futimes");
|
||||||
|
|
||||||
|
ua.path_format = 'i';
|
||||||
|
ua.path = (PyObject **)&fd;
|
||||||
|
ua.first_argument_name = "fd";
|
||||||
|
|
||||||
|
if (!utime_read_time_arguments(&ua))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (arg == Py_None) {
|
if (ua.now) {
|
||||||
/* optional time values not given */
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
res = futimes(fd, NULL);
|
res = futimes(fd, NULL);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
}
|
}
|
||||||
else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"futimes() arg 2 must be a tuple (atime, mtime)");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 0),
|
|
||||||
&atime, &ansec) == -1) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 1),
|
|
||||||
&mtime, &mnsec) == -1) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
{
|
{
|
||||||
#ifdef HAVE_FUTIMENS
|
#ifdef HAVE_FUTIMENS
|
||||||
struct timespec buf[2];
|
UA_TO_TIMESPEC(ua, buf);
|
||||||
buf[0].tv_sec = atime;
|
|
||||||
buf[0].tv_nsec = ansec;
|
|
||||||
buf[1].tv_sec = mtime;
|
|
||||||
buf[1].tv_nsec = mnsec;
|
|
||||||
res = futimens(fd, buf);
|
res = futimens(fd, buf);
|
||||||
#else
|
#else
|
||||||
struct timeval buf[2];
|
UA_TO_TIMEVAL(ua, buf);
|
||||||
buf[0].tv_sec = atime;
|
|
||||||
buf[0].tv_usec = ansec / 1000;
|
|
||||||
buf[1].tv_sec = mtime;
|
|
||||||
buf[1].tv_usec = mnsec / 1000;
|
|
||||||
res = futimes(fd, buf);
|
res = futimes(fd, buf);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -3806,61 +3912,40 @@ posix_futimes(PyObject *self, PyObject *args)
|
||||||
|
|
||||||
#ifdef HAVE_LUTIMES
|
#ifdef HAVE_LUTIMES
|
||||||
PyDoc_STRVAR(posix_lutimes__doc__,
|
PyDoc_STRVAR(posix_lutimes__doc__,
|
||||||
"lutimes(path[, (atime, mtime)])\n\
|
"lutimes(path[, times=(atime, mtime), *, ns=(atime_ns, mtime_ns)])\n\
|
||||||
Like utime(), but if path is a symbolic link, it is not dereferenced.");
|
Like utime(), but if path is a symbolic link, it is not dereferenced.");
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
posix_lutimes(PyObject *self, PyObject *args)
|
posix_lutimes(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
PyObject *opath;
|
PyObject *opath;
|
||||||
PyObject *arg = Py_None;
|
|
||||||
const char *path;
|
const char *path;
|
||||||
int res;
|
int res;
|
||||||
time_t atime, mtime;
|
|
||||||
long ansec, mnsec;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O&|O:lutimes",
|
DECLARE_UA(ua, "lutimes");
|
||||||
PyUnicode_FSConverter, &opath, &arg))
|
|
||||||
|
ua.path_format = 'O';
|
||||||
|
ua.path = &opath;
|
||||||
|
ua.converter = PyUnicode_FSConverter;
|
||||||
|
|
||||||
|
if (!utime_read_time_arguments(&ua))
|
||||||
return NULL;
|
return NULL;
|
||||||
path = PyBytes_AsString(opath);
|
path = PyBytes_AsString(opath);
|
||||||
if (arg == Py_None) {
|
|
||||||
|
if (ua.now) {
|
||||||
/* optional time values not given */
|
/* optional time values not given */
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
res = lutimes(path, NULL);
|
res = lutimes(path, NULL);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
}
|
}
|
||||||
else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"lutimes() arg 2 must be a tuple (atime, mtime)");
|
|
||||||
Py_DECREF(opath);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 0),
|
|
||||||
&atime, &ansec) == -1) {
|
|
||||||
Py_DECREF(opath);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 1),
|
|
||||||
&mtime, &mnsec) == -1) {
|
|
||||||
Py_DECREF(opath);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
{
|
{
|
||||||
#ifdef HAVE_UTIMENSAT
|
#ifdef HAVE_UTIMENSAT
|
||||||
struct timespec buf[2];
|
UA_TO_TIMESPEC(ua, buf);
|
||||||
buf[0].tv_sec = atime;
|
|
||||||
buf[0].tv_nsec = ansec;
|
|
||||||
buf[1].tv_sec = mtime;
|
|
||||||
buf[1].tv_nsec = mnsec;
|
|
||||||
res = utimensat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
|
res = utimensat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
|
||||||
#else
|
#else
|
||||||
struct timeval buf[2];
|
UA_TO_TIMEVAL(ua, buf);
|
||||||
buf[0].tv_sec = atime;
|
|
||||||
buf[0].tv_usec = ansec / 1000;
|
|
||||||
buf[1].tv_sec = mtime;
|
|
||||||
buf[1].tv_usec = mnsec / 1000;
|
|
||||||
res = lutimes(path, buf);
|
res = lutimes(path, buf);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -3873,62 +3958,6 @@ posix_lutimes(PyObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_FUTIMENS
|
|
||||||
PyDoc_STRVAR(posix_futimens__doc__,
|
|
||||||
"futimens(fd[, (atime_sec, atime_nsec), (mtime_sec, mtime_nsec)])\n\
|
|
||||||
Updates the timestamps of a file specified by the file descriptor fd, with\n\
|
|
||||||
nanosecond precision.\n\
|
|
||||||
If no second argument is given, set atime and mtime to the current time.\n\
|
|
||||||
If *_nsec is specified as UTIME_NOW, the timestamp is updated to the\n\
|
|
||||||
current time.\n\
|
|
||||||
If *_nsec is specified as UTIME_OMIT, the timestamp is not updated.");
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
posix_futimens(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
int res, fd;
|
|
||||||
PyObject *atime = Py_None;
|
|
||||||
PyObject *mtime = Py_None;
|
|
||||||
struct timespec buf[2];
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i|OO:futimens",
|
|
||||||
&fd, &atime, &mtime))
|
|
||||||
return NULL;
|
|
||||||
if (atime == Py_None && mtime == Py_None) {
|
|
||||||
/* optional time values not given */
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
|
||||||
res = futimens(fd, NULL);
|
|
||||||
Py_END_ALLOW_THREADS
|
|
||||||
}
|
|
||||||
else if (!PyTuple_Check(atime) || PyTuple_Size(atime) != 2) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"futimens() arg 2 must be a tuple (atime_sec, atime_nsec)");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else if (!PyTuple_Check(mtime) || PyTuple_Size(mtime) != 2) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"futimens() arg 3 must be a tuple (mtime_sec, mtime_nsec)");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!PyArg_ParseTuple(atime, "ll:futimens",
|
|
||||||
&(buf[0].tv_sec), &(buf[0].tv_nsec))) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (!PyArg_ParseTuple(mtime, "ll:futimens",
|
|
||||||
&(buf[1].tv_sec), &(buf[1].tv_nsec))) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
|
||||||
res = futimens(fd, buf);
|
|
||||||
Py_END_ALLOW_THREADS
|
|
||||||
}
|
|
||||||
if (res < 0)
|
|
||||||
return posix_error();
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Process operations */
|
/* Process operations */
|
||||||
|
|
||||||
PyDoc_STRVAR(posix__exit__doc__,
|
PyDoc_STRVAR(posix__exit__doc__,
|
||||||
|
@ -10619,15 +10648,15 @@ static PyMethodDef posix_methods[] = {
|
||||||
#endif /* HAVE_UNAME */
|
#endif /* HAVE_UNAME */
|
||||||
{"unlink", posix_unlink, METH_VARARGS, posix_unlink__doc__},
|
{"unlink", posix_unlink, METH_VARARGS, posix_unlink__doc__},
|
||||||
{"remove", posix_unlink, METH_VARARGS, posix_remove__doc__},
|
{"remove", posix_unlink, METH_VARARGS, posix_remove__doc__},
|
||||||
{"utime", posix_utime, METH_VARARGS, posix_utime__doc__},
|
{"utime", (PyCFunction)posix_utime,
|
||||||
|
METH_VARARGS | METH_KEYWORDS, posix_utime__doc__},
|
||||||
#ifdef HAVE_FUTIMES
|
#ifdef HAVE_FUTIMES
|
||||||
{"futimes", posix_futimes, METH_VARARGS, posix_futimes__doc__},
|
{"futimes", (PyCFunction)posix_futimes,
|
||||||
|
METH_VARARGS | METH_KEYWORDS, posix_futimes__doc__},
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LUTIMES
|
#ifdef HAVE_LUTIMES
|
||||||
{"lutimes", posix_lutimes, METH_VARARGS, posix_lutimes__doc__},
|
{"lutimes", (PyCFunction)posix_lutimes,
|
||||||
#endif
|
METH_VARARGS | METH_KEYWORDS, posix_lutimes__doc__},
|
||||||
#ifdef HAVE_FUTIMENS
|
|
||||||
{"futimens", posix_futimens, METH_VARARGS, posix_futimens__doc__},
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_TIMES
|
#ifdef HAVE_TIMES
|
||||||
{"times", posix_times, METH_NOARGS, posix_times__doc__},
|
{"times", posix_times, METH_NOARGS, posix_times__doc__},
|
||||||
|
|
|
@ -123,7 +123,7 @@ error_time_t_overflow(void)
|
||||||
"timestamp out of range for platform time_t");
|
"timestamp out of range for platform time_t");
|
||||||
}
|
}
|
||||||
|
|
||||||
static time_t
|
time_t
|
||||||
_PyLong_AsTime_t(PyObject *obj)
|
_PyLong_AsTime_t(PyObject *obj)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG
|
#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue