# HG changeset patch # User Steve Dower # Date 1426906246 25200 # Fri Mar 20 19:50:46 2015 -0700 # Node ID c7ae53d6deaa0ec73eb20b49ccdde2e96f492f6c # Parent 99eb196fb345c07f0bc7a7c438209bf3c435eb4f 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,11 @@ 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. + + .. versionchanged:: 3.5 + Windows will now zero-fill files when extending. .. 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 @@ -68,6 +68,8 @@ - Issue #2052: Add charset parameter to HtmlDiff.make_file(). +- 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 @@ -885,9 +885,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; @@ -910,52 +908,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 @@ -968,11 +920,13 @@ 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 @@ -2352,6 +2352,10 @@ #endif /*[python end generated code: output=4bd4f6f7d41267f1 input=80b4c890b6774ea5]*/ +#ifdef MS_WINDOWS + #undef PATH_HAVE_FTRUNCATE + #define PATH_HAVE_FTRUNCATE 1 +#endif /*[python input] @@ -12474,7 +12478,7 @@ #endif /* HAVE_DEVICE_MACROS */ -#ifdef HAVE_FTRUNCATE +#if defined HAVE_FTRUNCATE || defined MS_WINDOWS /*[clinic input] os.ftruncate @@ -12521,9 +12525,16 @@ int result; int async_err = 0; + if (!_PyVerify_fd(fd)) + return posix_error(); + 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())); @@ -12531,10 +12542,10 @@ return (!async_err) ? posix_error() : NULL; Py_RETURN_NONE; } -#endif /* HAVE_FTRUNCATE */ - - -#ifdef HAVE_TRUNCATE +#endif /* HAVE_FTRUNCATE || MS_WINDOWS */ + + +#if defined HAVE_TRUNCATE || defined MS_WINDOWS /*[clinic input] os.truncate path: path_t(allow_fd='PATH_HAVE_FTRUNCATE') @@ -12587,21 +12598,37 @@ /*[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 | _O_NOINHERIT); + else + fd = _open(path->narrow, _O_WRONLY | _O_BINARY | _O_NOINHERIT); + if (fd < 0) + result = -1; + else { + result = _chsize_s(fd, length); + close(fd); + if (result < 0) + errno = result; + } +#else + result = truncate(path->narrow, length); +#endif Py_END_ALLOW_THREADS if (result < 0) return path_error(path); Py_RETURN_NONE; } -#endif /* HAVE_TRUNCATE */ +#endif /* HAVE_TRUNCATE || MS_WINDOWS */ /* Issue #22396: On 32-bit AIX platform, the prototypes of os.posix_fadvise() @@ -18262,7 +18289,7 @@ "HAVE_FSTATVFS", #endif -#ifdef HAVE_FTRUNCATE +#if defined HAVE_FTRUNCATE || defined MS_WINDOWS "HAVE_FTRUNCATE", #endif