# HG changeset patch # Parent 812a0faa8fe3eaca4bc5f4f72abb850e38b85a59 Issue #23668: Adds support for os.truncate and os.ftruncate on Windows diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -339,8 +339,8 @@ if *size* is not specified). The current stream position isn't changed. This resizing can extend or reduce the current file size. In case of extension, the contents of the new file area depend on the platform - (on most systems, additional bytes are zero-filled, on Windows they're - undetermined). The new file size is returned. + (on most systems, additional bytes are zero-filled). The new file size + is returned. .. method:: writable() diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -805,8 +805,10 @@ most *length* bytes in size. As of Python 3.3, this is equivalent to ``os.truncate(fd, length)``. - Availability: Unix. - + Availability: Unix, Windows. + + .. versionchanged:: 3.5 + Added support for Windows .. function:: get_blocking(fd) @@ -2477,10 +2479,12 @@ This function can support :ref:`specifying a file descriptor `. - Availability: Unix. + Availability: Unix, Windows. .. versionadded:: 3.3 + .. versionchanged:: 3.5 + Added support for Windows .. function:: unlink(path, *, dir_fd=None) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,8 @@ Library ------- +- Issue #23668: Support os.truncate and os.ftruncate on Windows. + - Issue #23138: Fixed parsing cookies with absent keys or values in cookiejar. Patch by Demian Brecht. diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -28,13 +28,6 @@ * - autoconfify header file inclusion */ -#ifdef MS_WINDOWS -/* can simulate truncate with Win32 API functions; see file_truncate */ -#define HAVE_FTRUNCATE -#define WIN32_LEAN_AND_MEAN -#include -#endif - #if BUFSIZ < (8*1024) #define SMALLCHUNK (8*1024) #elif (BUFSIZ >= (2 << 25)) @@ -974,9 +967,7 @@ fileio_truncate(fileio *self, PyObject *args) { PyObject *posobj = NULL; /* the new size wanted by the user */ -#ifndef MS_WINDOWS Py_off_t pos; -#endif int ret; int fd; @@ -999,52 +990,6 @@ Py_INCREF(posobj); } -#ifdef MS_WINDOWS - /* MS _chsize doesn't work if newsize doesn't fit in 32 bits, - so don't even try using it. */ - { - PyObject *oldposobj, *tempposobj; - HANDLE hFile; - - /* we save the file pointer position */ - oldposobj = portable_lseek(fd, NULL, 1); - if (oldposobj == NULL) { - Py_DECREF(posobj); - return NULL; - } - - /* we then move to the truncation position */ - tempposobj = portable_lseek(fd, posobj, 0); - if (tempposobj == NULL) { - Py_DECREF(oldposobj); - Py_DECREF(posobj); - return NULL; - } - Py_DECREF(tempposobj); - - /* Truncate. Note that this may grow the file! */ - Py_BEGIN_ALLOW_THREADS - errno = 0; - hFile = (HANDLE)_get_osfhandle(fd); - ret = hFile == (HANDLE)-1; /* testing for INVALID_HANDLE value */ - if (ret == 0) { - ret = SetEndOfFile(hFile) == 0; - if (ret) - errno = EACCES; - } - Py_END_ALLOW_THREADS - - /* we restore the file pointer position in any case */ - tempposobj = portable_lseek(fd, oldposobj, 0); - Py_DECREF(oldposobj); - if (tempposobj == NULL) { - Py_DECREF(posobj); - return NULL; - } - Py_DECREF(tempposobj); - } -#else - #if defined(HAVE_LARGEFILE_SUPPORT) pos = PyLong_AsLongLong(posobj); #else @@ -1056,12 +1001,14 @@ } Py_BEGIN_ALLOW_THREADS errno = 0; +#ifdef MS_WINDOWS + ret = _chsize_s(fd, pos); +#else ret = ftruncate(fd, pos); +#endif Py_END_ALLOW_THREADS -#endif /* !MS_WINDOWS */ - if (ret != 0) { Py_DECREF(posobj); PyErr_SetFromErrno(PyExc_IOError); diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -12584,7 +12584,11 @@ do { Py_BEGIN_ALLOW_THREADS +#ifdef MS_WINDOWS + result = _chsize_s(fd, length); +#else result = ftruncate(fd, length); +#endif Py_END_ALLOW_THREADS } while (result != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); @@ -12648,14 +12654,29 @@ /*[clinic end generated code: output=6bd76262d2e027c6 input=77229cf0b50a9b77]*/ { int result; +#ifdef MS_WINDOWS + int fd; +#endif + + if (path->fd != -1) + return os_ftruncate_impl(module, path->fd, length); Py_BEGIN_ALLOW_THREADS -#ifdef HAVE_FTRUNCATE - if (path->fd != -1) - result = ftruncate(path->fd, length); - else -#endif - result = truncate(path->narrow, length); +#ifdef MS_WINDOWS + if (path->wide) + fd = _wopen(path->wide, _O_WRONLY | _O_BINARY); + else + fd = _open(path->narrow, _O_WRONLY | _O_BINARY); + if (fd < 0) + result = -1; + else { + if (_chsize_s(fd, length)) + result = -1; + close(fd); + } +#else + result = truncate(path->narrow, length); +#endif Py_END_ALLOW_THREADS if (result < 0) return path_error(path); diff --git a/PC/pyconfig.h b/PC/pyconfig.h --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -554,6 +554,9 @@ #define HAVE_FTIME #endif +/* Define if you have ftruncate (_chsize_s). */ +#define HAVE_FTRUNCATE + /* Define if you have getpeername. */ #define HAVE_GETPEERNAME @@ -613,6 +616,9 @@ /* Define if you have times. */ /* #undef HAVE_TIMES */ +/* Define if you have truncate (_chsize_s). */ +#define HAVE_TRUNCATE + /* Define if you have uname. */ /* #undef HAVE_UNAME */