diff options
author | Michael W. Hudson <mwh@python.net> | 2002-03-16 18:19:33 (GMT) |
---|---|---|
committer | Michael W. Hudson <mwh@python.net> | 2002-03-16 18:19:33 (GMT) |
commit | fe69139f7e960c52aab54e2b6b1026ced68024d4 (patch) | |
tree | 802fdfb9b3913f6d0b5b308334b6e6d76775a5e6 /Objects | |
parent | 13510e7afb849e7b934fdc946ca38738ed4ea4c4 (diff) | |
download | cpython-fe69139f7e960c52aab54e2b6b1026ced68024d4.zip cpython-fe69139f7e960c52aab54e2b6b1026ced68024d4.tar.gz cpython-fe69139f7e960c52aab54e2b6b1026ced68024d4.tar.bz2 |
Backport Tim's work on getting file.truncate working better on Win32.
"cvs diff | patch" managed to stick the NEWS item in the 2.2 final
section! I wonder which silly man wrote patch <wink>.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/fileobject.c | 84 |
1 files changed, 66 insertions, 18 deletions
diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 1430eef..138bdb6 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -10,8 +10,10 @@ #ifdef MS_WIN32 #define fileno _fileno -/* can (almost fully) duplicate with _chsize, see file_truncate */ +/* can simulate truncate with Win32 API functions; see file_truncate */ #define HAVE_FTRUNCATE +#define WINDOWS_LEAN_AND_MEAN +#include <windows.h> #endif #ifdef macintosh @@ -375,6 +377,9 @@ file_truncate(PyFileObject *f, PyObject *args) newsizeobj = NULL; if (!PyArg_ParseTuple(args, "|O:truncate", &newsizeobj)) return NULL; + + /* Set newsize to current postion if newsizeobj NULL, else to the + specified value. */ if (newsizeobj != NULL) { #if !defined(HAVE_LARGEFILE_SUPPORT) newsize = PyInt_AsLong(newsizeobj); @@ -385,37 +390,80 @@ file_truncate(PyFileObject *f, PyObject *args) #endif if (PyErr_Occurred()) return NULL; - } else { - /* Default to current position*/ + } + else { + /* Default to current position. */ Py_BEGIN_ALLOW_THREADS errno = 0; newsize = _portable_ftell(f->f_fp); Py_END_ALLOW_THREADS - if (newsize == -1) { - PyErr_SetFromErrno(PyExc_IOError); - clearerr(f->f_fp); - return NULL; - } + if (newsize == -1) + goto onioerror; } + + /* Flush the file. */ Py_BEGIN_ALLOW_THREADS errno = 0; ret = fflush(f->f_fp); Py_END_ALLOW_THREADS - if (ret != 0) goto onioerror; + if (ret != 0) + goto onioerror; #ifdef MS_WIN32 - /* can use _chsize; if, however, the newsize overflows 32-bits then - _chsize is *not* adequate; in this case, an OverflowError is raised */ - if (newsize > LONG_MAX) { - PyErr_SetString(PyExc_OverflowError, - "the new size is too long for _chsize (it is limited to 32-bit values)"); - return NULL; - } else { + /* MS _chsize doesn't work if newsize doesn't fit in 32 bits, + so don't even try using it. */ + { + Py_off_t current; /* current file position */ + HANDLE hFile; + int error; + + /* current <- current file postion. */ + if (newsizeobj == NULL) + current = newsize; + else { + Py_BEGIN_ALLOW_THREADS + errno = 0; + current = _portable_ftell(f->f_fp); + Py_END_ALLOW_THREADS + if (current == -1) + goto onioerror; + } + + /* Move to newsize. */ + if (current != newsize) { + Py_BEGIN_ALLOW_THREADS + errno = 0; + error = _portable_fseek(f->f_fp, newsize, SEEK_SET) + != 0; + Py_END_ALLOW_THREADS + if (error) + goto onioerror; + } + + /* Truncate. Note that this may grow the file! */ Py_BEGIN_ALLOW_THREADS errno = 0; - ret = _chsize(fileno(f->f_fp), (long)newsize); + hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp)); + error = hFile == (HANDLE)-1; + if (!error) { + error = SetEndOfFile(hFile) == 0; + if (error) + errno = EACCES; + } Py_END_ALLOW_THREADS - if (ret != 0) goto onioerror; + if (error) + goto onioerror; + + /* Restore original file position. */ + if (current != newsize) { + Py_BEGIN_ALLOW_THREADS + errno = 0; + error = _portable_fseek(f->f_fp, current, SEEK_SET) + != 0; + Py_END_ALLOW_THREADS + if (error) + goto onioerror; + } } #else Py_BEGIN_ALLOW_THREADS |