Issue #23668: Adds support for os.truncate and os.ftruncate on Windows

This commit is contained in:
Steve Dower 2015-03-20 19:50:46 -07:00
parent c7d979f022
commit fe0a41aae4
5 changed files with 53 additions and 63 deletions

View File

@ -339,8 +339,11 @@ I/O Base Classes
if *size* is not specified). The current stream position isn't changed. 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 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 extension, the contents of the new file area depend on the platform
(on most systems, additional bytes are zero-filled, on Windows they're (on most systems, additional bytes are zero-filled). The new file size
undetermined). The new file size is returned. is returned.
.. versionchanged:: 3.5
Windows will now zero-fill files when extending.
.. method:: writable() .. method:: writable()

View File

@ -805,8 +805,10 @@ as internal buffering of data.
most *length* bytes in size. As of Python 3.3, this is equivalent to most *length* bytes in size. As of Python 3.3, this is equivalent to
``os.truncate(fd, length)``. ``os.truncate(fd, length)``.
Availability: Unix. Availability: Unix, Windows.
.. versionchanged:: 3.5
Added support for Windows
.. function:: get_blocking(fd) .. function:: get_blocking(fd)
@ -2492,10 +2494,12 @@ features:
This function can support :ref:`specifying a file descriptor <path_fd>`. This function can support :ref:`specifying a file descriptor <path_fd>`.
Availability: Unix. Availability: Unix, Windows.
.. versionadded:: 3.3 .. versionadded:: 3.3
.. versionchanged:: 3.5
Added support for Windows
.. function:: unlink(path, *, dir_fd=None) .. function:: unlink(path, *, dir_fd=None)

View File

@ -286,6 +286,8 @@ Library
- Issue #2052: Add charset parameter to HtmlDiff.make_file(). - 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. - Issue #23138: Fixed parsing cookies with absent keys or values in cookiejar.
Patch by Demian Brecht. Patch by Demian Brecht.

View File

@ -839,9 +839,7 @@ static PyObject *
fileio_truncate(fileio *self, PyObject *args) fileio_truncate(fileio *self, PyObject *args)
{ {
PyObject *posobj = NULL; /* the new size wanted by the user */ PyObject *posobj = NULL; /* the new size wanted by the user */
#ifndef MS_WINDOWS
Py_off_t pos; Py_off_t pos;
#endif
int ret; int ret;
int fd; int fd;
@ -864,52 +862,6 @@ fileio_truncate(fileio *self, PyObject *args)
Py_INCREF(posobj); 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) #if defined(HAVE_LARGEFILE_SUPPORT)
pos = PyLong_AsLongLong(posobj); pos = PyLong_AsLongLong(posobj);
#else #else
@ -922,11 +874,13 @@ fileio_truncate(fileio *self, PyObject *args)
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
errno = 0; errno = 0;
#ifdef MS_WINDOWS
ret = _chsize_s(fd, pos);
#else
ret = ftruncate(fd, pos); ret = ftruncate(fd, pos);
#endif
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
#endif /* !MS_WINDOWS */
if (ret != 0) { if (ret != 0) {
Py_DECREF(posobj); Py_DECREF(posobj);
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_IOError);

View File

@ -2315,6 +2315,10 @@ FTRUNCATE
#endif #endif
/*[python end generated code: output=4bd4f6f7d41267f1 input=80b4c890b6774ea5]*/ /*[python end generated code: output=4bd4f6f7d41267f1 input=80b4c890b6774ea5]*/
#ifdef MS_WINDOWS
#undef PATH_HAVE_FTRUNCATE
#define PATH_HAVE_FTRUNCATE 1
#endif
/*[python input] /*[python input]
@ -8753,7 +8757,7 @@ os_makedev_impl(PyModuleDef *module, int major, int minor)
#endif /* HAVE_DEVICE_MACROS */ #endif /* HAVE_DEVICE_MACROS */
#ifdef HAVE_FTRUNCATE #if defined HAVE_FTRUNCATE || defined MS_WINDOWS
/*[clinic input] /*[clinic input]
os.ftruncate os.ftruncate
@ -8771,9 +8775,16 @@ os_ftruncate_impl(PyModuleDef *module, int fd, Py_off_t length)
int result; int result;
int async_err = 0; int async_err = 0;
if (!_PyVerify_fd(fd))
return posix_error();
do { do {
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
#ifdef MS_WINDOWS
result = _chsize_s(fd, length);
#else
result = ftruncate(fd, length); result = ftruncate(fd, length);
#endif
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
} while (result != 0 && errno == EINTR && } while (result != 0 && errno == EINTR &&
!(async_err = PyErr_CheckSignals())); !(async_err = PyErr_CheckSignals()));
@ -8781,10 +8792,10 @@ os_ftruncate_impl(PyModuleDef *module, int fd, Py_off_t length)
return (!async_err) ? posix_error() : NULL; return (!async_err) ? posix_error() : NULL;
Py_RETURN_NONE; Py_RETURN_NONE;
} }
#endif /* HAVE_FTRUNCATE */ #endif /* HAVE_FTRUNCATE || MS_WINDOWS */
#ifdef HAVE_TRUNCATE #if defined HAVE_TRUNCATE || defined MS_WINDOWS
/*[clinic input] /*[clinic input]
os.truncate os.truncate
path: path_t(allow_fd='PATH_HAVE_FTRUNCATE') path: path_t(allow_fd='PATH_HAVE_FTRUNCATE')
@ -8801,21 +8812,37 @@ os_truncate_impl(PyModuleDef *module, path_t *path, Py_off_t length)
/*[clinic end generated code: output=f60a9e08370e9e2e input=77229cf0b50a9b77]*/ /*[clinic end generated code: output=f60a9e08370e9e2e input=77229cf0b50a9b77]*/
{ {
int result; int result;
#ifdef MS_WINDOWS
int fd;
#endif
if (path->fd != -1)
return os_ftruncate_impl(module, path->fd, length);
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_FTRUNCATE #ifdef MS_WINDOWS
if (path->fd != -1) if (path->wide)
result = ftruncate(path->fd, length); fd = _wopen(path->wide, _O_WRONLY | _O_BINARY | _O_NOINHERIT);
else else
#endif 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); result = truncate(path->narrow, length);
#endif
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (result < 0) if (result < 0)
return path_error(path); return path_error(path);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
#endif /* HAVE_TRUNCATE */ #endif /* HAVE_TRUNCATE || MS_WINDOWS */
/* Issue #22396: On 32-bit AIX platform, the prototypes of os.posix_fadvise() /* Issue #22396: On 32-bit AIX platform, the prototypes of os.posix_fadvise()
@ -12771,7 +12798,7 @@ static char *have_functions[] = {
"HAVE_FSTATVFS", "HAVE_FSTATVFS",
#endif #endif
#ifdef HAVE_FTRUNCATE #if defined HAVE_FTRUNCATE || defined MS_WINDOWS
"HAVE_FTRUNCATE", "HAVE_FTRUNCATE",
#endif #endif