@@ -1400,6 +1400,31 @@ posix_uname(PyObject *self, PyObject *args)
14001400}
14011401#endif /* HAVE_UNAME */
14021402
1403+ static int
1404+ extract_time (PyObject * t , long * sec , long * usec )
1405+ {
1406+ long intval ;
1407+ if (PyFloat_Check (t )) {
1408+ double tval = PyFloat_AsDouble (t );
1409+ PyObject * intobj = t -> ob_type -> tp_as_number -> nb_int (t );
1410+ if (!intobj )
1411+ return -1 ;
1412+ intval = PyInt_AsLong (intobj );
1413+ Py_DECREF (intobj );
1414+ * sec = intval ;
1415+ * usec = (tval - intval ) * 1e6 ;
1416+ if (* usec < 0 )
1417+ /* If rounding gave us a negative number,
1418+ truncate. */
1419+ * usec = 0 ;
1420+ return 0 ;
1421+ }
1422+ intval = PyInt_AsLong (t );
1423+ if (intval == -1 && PyErr_Occurred ())
1424+ return -1 ;
1425+ * sec = intval ;
1426+ * usec = 0 ;
1427+ }
14031428
14041429PyDoc_STRVAR (posix_utime__doc__ ,
14051430"utime(path, (atime, utime))\n\
@@ -1411,22 +1436,26 @@ static PyObject *
14111436posix_utime (PyObject * self , PyObject * args )
14121437{
14131438 char * path ;
1414- long atime , mtime ;
1439+ long atime , mtime , ausec , musec ;
14151440 int res ;
14161441 PyObject * arg ;
14171442
1443+ #if defined(HAVE_UTIMES )
1444+ struct timeval buf [2 ];
1445+ #define ATIME buf[0].tv_sec
1446+ #define MTIME buf[1].tv_sec
1447+ #elif defined(HAVE_UTIME_H )
14181448/* XXX should define struct utimbuf instead, above */
1419- #ifdef HAVE_UTIME_H
14201449 struct utimbuf buf ;
14211450#define ATIME buf.actime
14221451#define MTIME buf.modtime
14231452#define UTIME_ARG &buf
1424- #else /* HAVE_UTIME_H */
1453+ #else /* HAVE_UTIMES */
14251454 time_t buf [2 ];
14261455#define ATIME buf[0]
14271456#define MTIME buf[1]
14281457#define UTIME_ARG buf
1429- #endif /* HAVE_UTIME_H */
1458+ #endif /* HAVE_UTIMES */
14301459
14311460 if (!PyArg_ParseTuple (args , "sO:utime" , & path , & arg ))
14321461 return NULL ;
@@ -1436,17 +1465,31 @@ posix_utime(PyObject *self, PyObject *args)
14361465 res = utime (path , NULL );
14371466 Py_END_ALLOW_THREADS
14381467 }
1439- else if (!PyArg_Parse (arg , "(ll)" , & atime , & mtime ) ) {
1468+ else if (!PyTuple_Check (arg ) || PyTuple_Size ( arg ) != 2 ) {
14401469 PyErr_SetString (PyExc_TypeError ,
14411470 "utime() arg 2 must be a tuple (atime, mtime)" );
14421471 return NULL ;
14431472 }
14441473 else {
1474+ if (extract_time (PyTuple_GET_ITEM (arg , 0 ),
1475+ & atime , & ausec ) == -1 )
1476+ return NULL ;
1477+ if (extract_time (PyTuple_GET_ITEM (arg , 1 ),
1478+ & mtime , & musec ) == -1 )
1479+ return NULL ;
14451480 ATIME = atime ;
14461481 MTIME = mtime ;
1482+ #ifdef HAVE_UTIMES
1483+ buf [0 ].tv_usec = ausec ;
1484+ buf [1 ].tv_usec = musec ;
1485+ Py_BEGIN_ALLOW_THREADS
1486+ res = utimes (path , buf );
1487+ Py_END_ALLOW_THREADS
1488+ #else
14471489 Py_BEGIN_ALLOW_THREADS
14481490 res = utime (path , UTIME_ARG );
14491491 Py_END_ALLOW_THREADS
1492+ #endif
14501493 }
14511494 if (res < 0 )
14521495 return posix_error_with_filename (path );
0 commit comments