]> granicus.if.org Git - python/commitdiff
(Merge 3.4) Issue #9246: On POSIX, os.getcwd() now supports paths longer than
authorVictor Stinner <victor.stinner@gmail.com>
Fri, 24 Apr 2015 22:21:52 +0000 (00:21 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Fri, 24 Apr 2015 22:21:52 +0000 (00:21 +0200)
1025 bytes. Patch written by William Orr.

1  2 
Misc/NEWS
Modules/posixmodule.c

diff --cc Misc/NEWS
index 4f702d05c2b8657927196f28f2d380f26f9baf9f,2616bf7d932525294adeaaf20bd4914ecbd309d7..c559ea528ad911eb60ace05daf89573537028045
+++ b/Misc/NEWS
@@@ -12,61 -12,6 +12,64 @@@ Core and Builtin
  
  - Issue #24022: Fix tokenizer crash when processing undecodable source code.
  
- - Issue #23887: urllib.error.HTTPError now has a proper repr() representation. 
 +Library
 +-------
 +
++- Issue #9246: On POSIX, os.getcwd() now supports paths longer than 1025 bytes.
++  Patch written by William Orr.
++
 +- Issue #17445: add difflib.diff_bytes() to support comparison of
 +  byte strings (fixes a regression from Python 2).
 +
 +- Issue #23917: Fall back to sequential compilation when ProcessPoolExecutor
 +  doesn't exist.  Patch by Claudiu Popa.
 +
 +- Issue #23008: Fixed resolving attributes with boolean value is False in pydoc.
 +
 +- Fix asyncio issue 235: LifoQueue and PriorityQueue's put didn't
 +  increment unfinished tasks (this bug was introduced when
 +  JoinableQueue was merged with Queue).
 +
 +- Issue #23908: os functions now reject paths with embedded null character
 +  on Windows instead of silently truncate them.
 +
 +- Issue #23728: binascii.crc_hqx() could return an integer outside of the range
 +  0-0xffff for empty data.
 +
++- Issue #23887: urllib.error.HTTPError now has a proper repr() representation.
 +  Patch by Berker Peksag.
 +
 +Documentation
 +-------------
 +
 +- Issue #24029: Document the name binding behavior for submodule imports.
 +
 +Tools/Demos
 +-----------
 +
 +- Issue #24031: make patchcheck now supports git checkouts, too.
 +
 +What's New in Python 3.5.0 alpha 4?
 +===================================
 +
 +Release date: 2015-04-19
 +
 +Core and Builtins
 +-----------------
 +
 +- Issue #22980: Under Linux, GNU/KFreeBSD and the Hurd, C extensions now include
 +  the architecture triplet in the extension name, to make it easy to test builds
 +  for different ABIs in the same working tree.  Under OS X, the extension name
 +  now includes PEP 3149-style information.
 +
 +- Issue #22631: Added Linux-specific socket constant CAN_RAW_FD_FRAMES.
 +  Patch courtesy of Joe Jevnik.
 +
 +- Issue #23731: Implement PEP 488: removal of .pyo files.
 +
 +- Issue #23726: Don't enable GC for user subclasses of non-GC types that
 +  don't add any new fields.  Patch by Eugene Toder.
 +
  - Issue #23309: Avoid a deadlock at shutdown if a daemon thread is aborted
    while it is holding a lock to a buffered I/O object, and the main thread
    tries to use the same I/O object (typically stdout or stderr).  A fatal
index ce34b3b0b80562e6167200a9c16362f31c5a9f24,04f0d3639cf88d751f9b06eecd66fd7936cc258b..3bed9583a93a620cdfab4421825e65b6c439aaa4
@@@ -3306,26 -3460,39 +3309,43 @@@ posix_getcwd(int use_bytes
          return NULL;
  #endif
  
+     buf = cwd = NULL;
      Py_BEGIN_ALLOW_THREADS
-     res = getcwd(buf, sizeof buf);
+     do {
+         buflen += chunk;
+         tmpbuf = PyMem_RawRealloc(buf, buflen);
+         if (tmpbuf == NULL)
+             break;
+         buf = tmpbuf;
+         cwd = getcwd(buf, buflen);
+     } while (cwd == NULL && errno == ERANGE);
      Py_END_ALLOW_THREADS
-     if (res == NULL)
+     if (cwd == NULL) {
+         PyMem_RawFree(buf);
          return posix_error();
+     }
      if (use_bytes)
-         return PyBytes_FromStringAndSize(buf, strlen(buf));
-     return PyUnicode_DecodeFSDefault(buf);
+         obj = PyBytes_FromStringAndSize(buf, strlen(buf));
+     else
+         obj = PyUnicode_DecodeFSDefault(buf);
+     PyMem_RawFree(buf);
+     return obj;
  }
  
 -PyDoc_STRVAR(posix_getcwd__doc__,
 -"getcwd() -> path\n\n\
 -Return a unicode string representing the current working directory.");
 +
 +/*[clinic input]
 +os.getcwd
 +
 +Return a unicode string representing the current working directory.
 +[clinic start generated code]*/
  
  static PyObject *
 -posix_getcwd_unicode(PyObject *self)
 +os_getcwd_impl(PyModuleDef *module)
 +/*[clinic end generated code: output=efe3a8c0121525ea input=f069211bb70e3d39]*/
  {
      return posix_getcwd(0);
  }
@@@ -8559,344 -8530,310 +8579,344 @@@ os_pipe2_impl(PyModuleDef *module, int 
  }
  #endif /* HAVE_PIPE2 */
  
 +
  #ifdef HAVE_WRITEV
 -PyDoc_STRVAR(posix_writev__doc__,
 -"writev(fd, buffers) -> byteswritten\n\n\
 -Write the contents of *buffers* to file descriptor *fd*. *buffers*\n\
 -must be a sequence of bytes-like objects.\n\n\
 -writev writes the contents of each object to the file descriptor\n\
 -and returns the total number of bytes written.");
 +/*[clinic input]
 +os.writev -> Py_ssize_t
 +    fd: int
 +    buffers: object
 +    /
  
 -static PyObject *
 -posix_writev(PyObject *self, PyObject *args)
 +Iterate over buffers, and write the contents of each to a file descriptor.
 +
 +Returns the total number of bytes written.
 +buffers must be a sequence of bytes-like objects.
 +[clinic start generated code]*/
 +
 +static Py_ssize_t
 +os_writev_impl(PyModuleDef *module, int fd, PyObject *buffers)
 +/*[clinic end generated code: output=a48925dbf2d5c238 input=5b8d17fe4189d2fe]*/
  {
 -    int fd, cnt;
 -    Py_ssize_t res;
 -    PyObject *seq;
 +    int cnt;
 +    Py_ssize_t result;
 +    int async_err = 0;
      struct iovec *iov;
      Py_buffer *buf;
 -    if (!PyArg_ParseTuple(args, "iO:writev", &fd, &seq))
 -        return NULL;
 -    if (!PySequence_Check(seq)) {
 +
 +    if (!PySequence_Check(buffers)) {
          PyErr_SetString(PyExc_TypeError,
              "writev() arg 2 must be a sequence");
 -        return NULL;
 +        return -1;
      }
 -    cnt = PySequence_Size(seq);
 +    cnt = PySequence_Size(buffers);
  
 -    if (iov_setup(&iov, &buf, seq, cnt, PyBUF_SIMPLE) < 0) {
 -        return NULL;
 +    if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_SIMPLE) < 0) {
 +        return -1;
      }
  
 -    Py_BEGIN_ALLOW_THREADS
 -    res = writev(fd, iov, cnt);
 -    Py_END_ALLOW_THREADS
 +    do {
 +        Py_BEGIN_ALLOW_THREADS
 +        result = writev(fd, iov, cnt);
 +        Py_END_ALLOW_THREADS
 +    } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
  
      iov_cleanup(iov, buf, cnt);
 -    if (res < 0)
 -        return posix_error();
 +    if (result < 0 && !async_err)
 +        posix_error();
  
 -    return PyLong_FromSsize_t(res);
 +    return result;
  }
 -#endif
 +#endif /* HAVE_WRITEV */
 +
  
  #ifdef HAVE_PWRITE
 -PyDoc_STRVAR(posix_pwrite__doc__,
 -"pwrite(fd, string, offset) -> byteswritten\n\n\
 -Write string to a file descriptor, fd, from offset, leaving the file\n\
 -offset unchanged.");
 +/*[clinic input]
 +os.pwrite -> Py_ssize_t
  
 -static PyObject *
 -posix_pwrite(PyObject *self, PyObject *args)
 +    fd: int
 +    buffer: Py_buffer
 +    offset: Py_off_t
 +    /
 +
 +Write bytes to a file descriptor starting at a particular offset.
 +
 +Write buffer to fd, starting at offset bytes from the beginning of
 +the file.  Returns the number of bytes writte.  Does not change the
 +current file offset.
 +[clinic start generated code]*/
 +
 +static Py_ssize_t
 +os_pwrite_impl(PyModuleDef *module, int fd, Py_buffer *buffer,
 +               Py_off_t offset)
 +/*[clinic end generated code: output=93aabdb40e17d325 input=19903f1b3dd26377]*/
  {
 -    Py_buffer pbuf;
 -    int fd;
 -    off_t offset;
      Py_ssize_t size;
 -
 -    if (!PyArg_ParseTuple(args, "iy*O&:pwrite", &fd, &pbuf, _parse_off_t, &offset))
 -        return NULL;
 +    int async_err = 0;
  
      if (!_PyVerify_fd(fd)) {
 -        PyBuffer_Release(&pbuf);
 -        return posix_error();
 +        posix_error();
 +        return -1;
      }
 -    Py_BEGIN_ALLOW_THREADS
 -    size = pwrite(fd, pbuf.buf, (size_t)pbuf.len, offset);
 -    Py_END_ALLOW_THREADS
 -    PyBuffer_Release(&pbuf);
 -    if (size < 0)
 -        return posix_error();
 -    return PyLong_FromSsize_t(size);
 +
 +    do {
 +        Py_BEGIN_ALLOW_THREADS
 +        _Py_BEGIN_SUPPRESS_IPH
 +        size = pwrite(fd, buffer->buf, (size_t)buffer->len, offset);
 +        _Py_END_SUPPRESS_IPH
 +        Py_END_ALLOW_THREADS
 +    } while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
 +
 +    if (size < 0 && !async_err)
 +        posix_error();
 +    return size;
  }
 -#endif
 +#endif /* HAVE_PWRITE */
 +
  
  #ifdef HAVE_MKFIFO
 -PyDoc_STRVAR(posix_mkfifo__doc__,
 -"mkfifo(path, mode=0o666, *, dir_fd=None)\n\n\
 -Create a FIFO (a POSIX named pipe).\n\
 -\n\
 -If dir_fd is not None, it should be a file descriptor open to a directory,\n\
 -  and path should be relative; path will then be relative to that directory.\n\
 -dir_fd may not be implemented on your platform.\n\
 -  If it is unavailable, using it will raise a NotImplementedError.");
 +/*[clinic input]
 +os.mkfifo
 +
 +    path: path_t
 +    mode: int=0o666
 +    *
 +    dir_fd: dir_fd(requires='mkfifoat')=None
 +
 +Create a "fifo" (a POSIX named pipe).
 +
 +If dir_fd is not None, it should be a file descriptor open to a directory,
 +  and path should be relative; path will then be relative to that directory.
 +dir_fd may not be implemented on your platform.
 +  If it is unavailable, using it will raise a NotImplementedError.
 +[clinic start generated code]*/
  
  static PyObject *
 -posix_mkfifo(PyObject *self, PyObject *args, PyObject *kwargs)
 +os_mkfifo_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd)
 +/*[clinic end generated code: output=8f5f5e72c630049a input=73032e98a36e0e19]*/
  {
 -    path_t path;
 -    int mode = 0666;
 -    int dir_fd = DEFAULT_DIR_FD;
      int result;
 -    PyObject *return_value = NULL;
 -    static char *keywords[] = {"path", "mode", "dir_fd", NULL};
 +    int async_err = 0;
  
 -    memset(&path, 0, sizeof(path));
 -    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|i$O&:mkfifo", keywords,
 -        path_converter, &path,
 -        &mode,
 +    do {
 +        Py_BEGIN_ALLOW_THREADS
  #ifdef HAVE_MKFIFOAT
 -        dir_fd_converter, &dir_fd
 -#else
 -        dir_fd_unavailable, &dir_fd
 +        if (dir_fd != DEFAULT_DIR_FD)
 +            result = mkfifoat(dir_fd, path->narrow, mode);
 +        else
  #endif
 -        ))
 -        return NULL;
 +            result = mkfifo(path->narrow, mode);
 +        Py_END_ALLOW_THREADS
 +    } while (result != 0 && errno == EINTR &&
 +             !(async_err = PyErr_CheckSignals()));
 +    if (result != 0)
 +        return (!async_err) ? posix_error() : NULL;
  
 -    Py_BEGIN_ALLOW_THREADS
 -#ifdef HAVE_MKFIFOAT
 -    if (dir_fd != DEFAULT_DIR_FD)
 -        result = mkfifoat(dir_fd, path.narrow, mode);
 -    else
 -#endif
 -        result = mkfifo(path.narrow, mode);
 -    Py_END_ALLOW_THREADS
 +    Py_RETURN_NONE;
 +}
 +#endif /* HAVE_MKFIFO */
  
 -    if (result < 0) {
 -        return_value = posix_error();
 -        goto exit;
 -    }
  
 -    return_value = Py_None;
 -    Py_INCREF(Py_None);
 +#if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV)
 +/*[clinic input]
 +os.mknod
  
 -exit:
 -    path_cleanup(&path);
 -    return return_value;
 -}
 -#endif
 +    path: path_t
 +    mode: int=0o600
 +    device: dev_t=0
 +    *
 +    dir_fd: dir_fd(requires='mknodat')=None
  
 -#if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV)
 -PyDoc_STRVAR(posix_mknod__doc__,
 -"mknod(filename, mode=0o600, device=0, *, dir_fd=None)\n\n\
 -Create a filesystem node (file, device special file or named pipe)\n\
 -named filename. mode specifies both the permissions to use and the\n\
 -type of node to be created, being combined (bitwise OR) with one of\n\
 -S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. For S_IFCHR and S_IFBLK,\n\
 -device defines the newly created device special file (probably using\n\
 -os.makedev()), otherwise it is ignored.\n\
 -\n\
 -If dir_fd is not None, it should be a file descriptor open to a directory,\n\
 -  and path should be relative; path will then be relative to that directory.\n\
 -dir_fd may not be implemented on your platform.\n\
 -  If it is unavailable, using it will raise a NotImplementedError.");
 +Create a node in the file system.
 +
 +Create a node in the file system (file, device special file or named pipe)
 +at path.  mode specifies both the permissions to use and the
 +type of node to be created, being combined (bitwise OR) with one of
 +S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO.  If S_IFCHR or S_IFBLK is set on mode,
 +device defines the newly created device special file (probably using
 +os.makedev()).  Otherwise device is ignored.
  
 +If dir_fd is not None, it should be a file descriptor open to a directory,
 +  and path should be relative; path will then be relative to that directory.
 +dir_fd may not be implemented on your platform.
 +  If it is unavailable, using it will raise a NotImplementedError.
 +[clinic start generated code]*/
  
  static PyObject *
 -posix_mknod(PyObject *self, PyObject *args, PyObject *kwargs)
 +os_mknod_impl(PyModuleDef *module, path_t *path, int mode, dev_t device,
 +              int dir_fd)
 +/*[clinic end generated code: output=5151a8a9f754d272 input=ee44531551a4d83b]*/
  {
 -    path_t path;
 -    int mode = 0666;
 -    dev_t device = 0;
 -    int dir_fd = DEFAULT_DIR_FD;
      int result;
 -    PyObject *return_value = NULL;
 -    static char *keywords[] = {"path", "mode", "device", "dir_fd", NULL};
 +    int async_err = 0;
  
 -    memset(&path, 0, sizeof(path));
 -    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|iO&$O&:mknod", keywords,
 -        path_converter, &path,
 -        &mode, _Py_Dev_Converter, &device,
 +    do {
 +        Py_BEGIN_ALLOW_THREADS
  #ifdef HAVE_MKNODAT
 -        dir_fd_converter, &dir_fd
 -#else
 -        dir_fd_unavailable, &dir_fd
 +        if (dir_fd != DEFAULT_DIR_FD)
 +            result = mknodat(dir_fd, path->narrow, mode, device);
 +        else
  #endif
 -        ))
 -        return NULL;
 +            result = mknod(path->narrow, mode, device);
 +        Py_END_ALLOW_THREADS
 +    } while (result != 0 && errno == EINTR &&
 +             !(async_err = PyErr_CheckSignals()));
 +    if (result != 0)
 +        return (!async_err) ? posix_error() : NULL;
  
 -    Py_BEGIN_ALLOW_THREADS
 -#ifdef HAVE_MKNODAT
 -    if (dir_fd != DEFAULT_DIR_FD)
 -        result = mknodat(dir_fd, path.narrow, mode, device);
 -    else
 -#endif
 -        result = mknod(path.narrow, mode, device);
 -    Py_END_ALLOW_THREADS
 +    Py_RETURN_NONE;
 +}
 +#endif /* defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) */
  
 -    if (result < 0) {
 -        return_value = posix_error();
 -        goto exit;
 -    }
  
 -    return_value = Py_None;
 -    Py_INCREF(Py_None);
 +#ifdef HAVE_DEVICE_MACROS
 +/*[clinic input]
 +os.major -> unsigned_int
  
 -exit:
 -    path_cleanup(&path);
 -    return return_value;
 -}
 -#endif
 +    device: dev_t
 +    /
  
 -#ifdef HAVE_DEVICE_MACROS
 -PyDoc_STRVAR(posix_major__doc__,
 -"major(device) -> major number\n\
 -Extracts a device major number from a raw device number.");
 +Extracts a device major number from a raw device number.
 +[clinic start generated code]*/
  
 -static PyObject *
 -posix_major(PyObject *self, PyObject *args)
 +static unsigned int
 +os_major_impl(PyModuleDef *module, dev_t device)
 +/*[clinic end generated code: output=ba55693ab49bac34 input=1e16a4d30c4d4462]*/
  {
 -    dev_t device;
 -    if (!PyArg_ParseTuple(args, "O&:major", _Py_Dev_Converter, &device))
 -        return NULL;
 -    return PyLong_FromLong((long)major(device));
 +    return major(device);
  }
  
 -PyDoc_STRVAR(posix_minor__doc__,
 -"minor(device) -> minor number\n\
 -Extracts a device minor number from a raw device number.");
  
 -static PyObject *
 -posix_minor(PyObject *self, PyObject *args)
 +/*[clinic input]
 +os.minor -> unsigned_int
 +
 +    device: dev_t
 +    /
 +
 +Extracts a device minor number from a raw device number.
 +[clinic start generated code]*/
 +
 +static unsigned int
 +os_minor_impl(PyModuleDef *module, dev_t device)
 +/*[clinic end generated code: output=2867219ebf274e27 input=0842c6d23f24c65e]*/
  {
 -    dev_t device;
 -    if (!PyArg_ParseTuple(args, "O&:minor", _Py_Dev_Converter, &device))
 -        return NULL;
 -    return PyLong_FromLong((long)minor(device));
 +    return minor(device);
  }
  
 -PyDoc_STRVAR(posix_makedev__doc__,
 -"makedev(major, minor) -> device number\n\
 -Composes a raw device number from the major and minor device numbers.");
  
 -static PyObject *
 -posix_makedev(PyObject *self, PyObject *args)
 +/*[clinic input]
 +os.makedev -> dev_t
 +
 +    major: int
 +    minor: int
 +    /
 +
 +Composes a raw device number from the major and minor device numbers.
 +[clinic start generated code]*/
 +
 +static dev_t
 +os_makedev_impl(PyModuleDef *module, int major, int minor)
 +/*[clinic end generated code: output=7cb6264352437660 input=4b9fd8fc73cbe48f]*/
  {
 -    int major, minor;
 -    if (!PyArg_ParseTuple(args, "ii:makedev", &major, &minor))
 -        return NULL;
 -    return _PyLong_FromDev(makedev(major, minor));
 +    return makedev(major, minor);
  }
 -#endif /* device macros */
 +#endif /* HAVE_DEVICE_MACROS */
  
  
 -#ifdef HAVE_FTRUNCATE
 -PyDoc_STRVAR(posix_ftruncate__doc__,
 -"ftruncate(fd, length)\n\n\
 -Truncate a file to a specified length.");
 +#if defined HAVE_FTRUNCATE || defined MS_WINDOWS
 +/*[clinic input]
 +os.ftruncate
 +
 +    fd: int
 +    length: Py_off_t
 +    /
 +
 +Truncate a file, specified by file descriptor, to a specific length.
 +[clinic start generated code]*/
  
  static PyObject *
 -posix_ftruncate(PyObject *self, PyObject *args)
 +os_ftruncate_impl(PyModuleDef *module, int fd, Py_off_t length)
 +/*[clinic end generated code: output=3666f401d76bf834 input=63b43641e52818f2]*/
  {
 -    int fd;
 -    off_t length;
 -    int res;
 -
 -    if (!PyArg_ParseTuple(args, "iO&:ftruncate", &fd, _parse_off_t, &length))
 -        return NULL;
 +    int result;
 +    int async_err = 0;
  
 -    Py_BEGIN_ALLOW_THREADS
 -    res = ftruncate(fd, length);
 -    Py_END_ALLOW_THREADS
 -    if (res < 0)
 +    if (!_PyVerify_fd(fd))
          return posix_error();
 -    Py_INCREF(Py_None);
 -    return Py_None;
 -}
 +
 +    do {
 +        Py_BEGIN_ALLOW_THREADS
 +        _Py_BEGIN_SUPPRESS_IPH
 +#ifdef MS_WINDOWS
 +        result = _chsize_s(fd, length);
 +#else
 +        result = ftruncate(fd, length);
  #endif
 +        _Py_END_SUPPRESS_IPH
 +        Py_END_ALLOW_THREADS
 +    } while (result != 0 && errno == EINTR &&
 +             !(async_err = PyErr_CheckSignals()));
 +    if (result != 0)
 +        return (!async_err) ? posix_error() : NULL;
 +    Py_RETURN_NONE;
 +}
 +#endif /* HAVE_FTRUNCATE || MS_WINDOWS */
 +
 +
 +#if defined HAVE_TRUNCATE || defined MS_WINDOWS
 +/*[clinic input]
 +os.truncate
 +    path: path_t(allow_fd='PATH_HAVE_FTRUNCATE')
 +    length: Py_off_t
 +
 +Truncate a file, specified by path, to a specific length.
  
 -#ifdef HAVE_TRUNCATE
 -PyDoc_STRVAR(posix_truncate__doc__,
 -"truncate(path, length)\n\n\
 -Truncate the file given by path to length bytes.\n\
 -On some platforms, path may also be specified as an open file descriptor.\n\
 -  If this functionality is unavailable, using it raises an exception.");
 +On some platforms, path may also be specified as an open file descriptor.
 +  If this functionality is unavailable, using it raises an exception.
 +[clinic start generated code]*/
  
  static PyObject *
 -posix_truncate(PyObject *self, PyObject *args, PyObject *kwargs)
 +os_truncate_impl(PyModuleDef *module, path_t *path, Py_off_t length)
 +/*[clinic end generated code: output=f60a9e08370e9e2e input=77229cf0b50a9b77]*/
  {
 -    path_t path;
 -    off_t length;
 -    int res;
 -    PyObject *result = NULL;
 -    static char *keywords[] = {"path", "length", NULL};
 -
 -    memset(&path, 0, sizeof(path));
 -    path.function_name = "truncate";
 -#ifdef HAVE_FTRUNCATE
 -    path.allow_fd = 1;
 +    int result;
 +#ifdef MS_WINDOWS
 +    int fd;
  #endif
 -    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&:truncate", keywords,
 -                                     path_converter, &path,
 -                                     _parse_off_t, &length))
 -        return NULL;
 +
 +    if (path->fd != -1)
 +        return os_ftruncate_impl(module, path->fd, length);
  
      Py_BEGIN_ALLOW_THREADS
 -#ifdef HAVE_FTRUNCATE
 -    if (path.fd != -1)
 -        res = ftruncate(path.fd, length);
 +    _Py_BEGIN_SUPPRESS_IPH
 +#ifdef MS_WINDOWS
 +    if (path->wide)
 +        fd = _wopen(path->wide, _O_WRONLY | _O_BINARY | _O_NOINHERIT);
      else
 -#endif
 -        res = truncate(path.narrow, length);
 -    Py_END_ALLOW_THREADS
 -    if (res < 0)
 -        result = path_error(&path);
 +        fd = _open(path->narrow, _O_WRONLY | _O_BINARY | _O_NOINHERIT);
-     if (fd < 0) 
++    if (fd < 0)
 +        result = -1;
      else {
 -        Py_INCREF(Py_None);
 -        result = Py_None;
 +        result = _chsize_s(fd, length);
 +        close(fd);
 +        if (result < 0)
 +            errno = result;
      }
 -    path_cleanup(&path);
 -    return result;
 -}
 +#else
 +    result = truncate(path->narrow, length);
  #endif
 +    _Py_END_SUPPRESS_IPH
 +    Py_END_ALLOW_THREADS
 +    if (result < 0)
 +        return path_error(path);
  
 -/* Issue #22396: On 32-bit AIX platform, the prototypes of os.posix_fadvise()
 -   and os.posix_fallocate() in system headers are wrong if _LARGE_FILES is
 -   defined, which is the case in Python on AIX. AIX bug report:
 +    Py_RETURN_NONE;
 +}
 +#endif /* HAVE_TRUNCATE || MS_WINDOWS */
 +
 +
 +/* Issue #22396: On 32-bit AIX platform, the prototypes of os.posix_fadvise()
 +   and os.posix_fallocate() in system headers are wrong if _LARGE_FILES is
 +   defined, which is the case in Python on AIX. AIX bug report:
     http://www-01.ibm.com/support/docview.wss?uid=isg1IV56170 */
  #if defined(_AIX) && defined(_LARGE_FILES) && !defined(__64BIT__)
  #  define POSIX_FADVISE_AIX_BUG