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 | |
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>.
-rw-r--r-- | Doc/lib/libstdtypes.tex | 34 | ||||
-rw-r--r-- | Lib/test/test_largefile.py | 45 | ||||
-rw-r--r-- | Misc/NEWS | 12 | ||||
-rw-r--r-- | Objects/fileobject.c | 84 |
4 files changed, 127 insertions, 48 deletions
diff --git a/Doc/lib/libstdtypes.tex b/Doc/lib/libstdtypes.tex index 2ba87c4..2bd6420 100644 --- a/Doc/lib/libstdtypes.tex +++ b/Doc/lib/libstdtypes.tex @@ -161,7 +161,7 @@ only by sequence types (below). \subsection{Numeric Types \label{typesnumeric}} -There are four numeric types: \dfn{plain integers}, \dfn{long integers}, +There are four numeric types: \dfn{plain integers}, \dfn{long integers}, \dfn{floating point numbers}, and \dfn{complex numbers}. Plain integers (also just called \dfn{integers}) are implemented using \ctype{long} in C, which gives them at least 32 @@ -178,7 +178,7 @@ working with. Complex numbers have a real and imaginary part, which are both implemented using \ctype{double} in C. To extract these parts from -a complex number \var{z}, use \code{\var{z}.real} and \code{\var{z}.imag}. +a complex number \var{z}, use \code{\var{z}.real} and \code{\var{z}.imag}. Numbers are created by numeric literals or as the result of built-in functions and operators. Unadorned integer literals (including hex @@ -248,7 +248,7 @@ Notes: \item[(1)] For (plain or long) integer division, the result is an integer. -The result is always rounded towards minus infinity: 1/2 is 0, +The result is always rounded towards minus infinity: 1/2 is 0, (-1)/2 is -1, 1/(-2) is -1, and (-1)/(-2) is 0. Note that the result is a long integer if either operand is a long integer, regardless of the numeric value. @@ -472,7 +472,7 @@ Notes: the end of the string: \code{len(\var{s}) + \var{i}} or \code{len(\var{s}) + \var{j}} is substituted. But note that \code{-0} is still \code{0}. - + \item[(3)] The slice of \var{s} from \var{i} to \var{j} is defined as the sequence of items with index \var{k} such that \code{\var{i} <= \var{k} < \var{j}}. If \var{i} or \var{j} is greater than @@ -808,7 +808,7 @@ are replaced by \code{\%g} conversions.\footnote{ Additional string operations are defined in standard modules \refmodule{string}\refstmodindex{string} and -\refmodule{re}.\refstmodindex{re} +\refmodule{re}.\refstmodindex{re} \subsubsection{XRange Type \label{typesseq-xrange}} @@ -881,7 +881,7 @@ Notes: no longer works in Python 2.0. Use of this misfeature has been deprecated since Python 1.4. -\item[(2)] Raises an exception when \var{x} is not a list object. The +\item[(2)] Raises an exception when \var{x} is not a list object. The \method{extend()} method is experimental and not supported by mutable sequence types other than lists. @@ -1034,7 +1034,7 @@ over a dictionary, as often used in set algorithms. File objects\obindex{file} are implemented using C's \code{stdio} package and can be created with the built-in constructor -\function{file()}\bifuncindex{file} described in section +\function{file()}\bifuncindex{file} described in section \ref{built-in-funcs}, ``Built-in Functions.''\footnote{\function{file()} is new in Python 2.2. The older built-in \function{open()} is an alias for \function{file()}.} @@ -1100,10 +1100,10 @@ Files have the following methods: \begin{methoddesc}[file]{readline}{\optional{size}} Read one entire line from the file. A trailing newline character is kept in the string\footnote{ - The advantage of leaving the newline on is that an empty string - can be returned to mean \EOF{} without being ambiguous. Another - advantage is that (in cases where it might matter, for example. if you - want to make an exact copy of a file while scanning its lines) + The advantage of leaving the newline on is that an empty string + can be returned to mean \EOF{} without being ambiguous. Another + advantage is that (in cases where it might matter, for example. if you + want to make an exact copy of a file while scanning its lines) you can tell whether the last line of a file ended in a newline or not (yes this happens!). } (but may be absent when a file ends with an @@ -1152,11 +1152,15 @@ Files have the following methods: \end{methoddesc} \begin{methoddesc}[file]{truncate}{\optional{size}} - Truncate the file's size. If the optional \var{size} argument + Truncate the file's size. If the optional \var{size} argument is present, the file is truncated to (at most) that size. The size - defaults to the current position. Availability of this function - depends on the operating system version (for example, not all - \UNIX{} versions support this operation). + defaults to the current position. The current file position is + not changed. Note that if a specified size exceeds the file's + current size, the result is platform-dependent: possibilities + include that file may remain unchanged, increase to the specified + size as if zero-filled, or increase to the specified size with + undefined new content. + Availability: Windows, many \UNIX variants. \end{methoddesc} \begin{methoddesc}[file]{write}{str} diff --git a/Lib/test/test_largefile.py b/Lib/test/test_largefile.py index abfee39..8bff5df 100644 --- a/Lib/test/test_largefile.py +++ b/Lib/test/test_largefile.py @@ -128,20 +128,35 @@ expect(os.lseek(f.fileno(), size, 0), size) expect(f.read(1), 'a') # the 'a' that was written at the end of the file above f.close() - -# XXX add tests for truncate if it exists -# XXX has truncate ever worked on Windows? specifically on WinNT I get: -# "IOError: [Errno 13] Permission denied" -##try: -## newsize = size - 10 -## f.seek(newsize) -## f.truncate() -## expect(f.tell(), newsize) -## newsize = newsize - 1 -## f.seek(0) -## f.truncate(newsize) -## expect(f.tell(), newsize) -##except AttributeError: -## pass +if hasattr(f, 'truncate'): + if test_support.verbose: + print 'try truncate' + f = open(name, 'r+b') + f.seek(0, 2) + expect(f.tell(), size+1) # else we've lost track of the true size + # Cut it back via seek + truncate with no argument. + newsize = size - 10 + f.seek(newsize) + f.truncate() + expect(f.tell(), newsize) # else pointer moved + f.seek(0, 2) + expect(f.tell(), newsize) # else wasn't truncated + # Ensure that truncate(smaller than true size) shrinks the file. + newsize -= 1 + f.seek(42) + f.truncate(newsize) + expect(f.tell(), 42) # else pointer moved + f.seek(0, 2) + expect(f.tell(), newsize) # else wasn't truncated + + # XXX truncate(larger than true size) is ill-defined across platforms + + # cut it waaaaay back + f.seek(0) + f.truncate(1) + expect(f.tell(), 0) # else pointer moved + expect(len(f.read()), 1) # else wasn't truncated + + f.close() os.unlink(name) @@ -4,6 +4,12 @@ Release date: XXX Core and builtins +- If you try to pickle an instance of a class that has __slots__ but + doesn't define or override __getstate__, a TypeError is now raised. + This is done by adding a bozo __getstate__ to the class that always + raises TypeError. (Before, this would appear to be pickled, but the + state of the slots would be lost.) + - PyErr_Display will provide file and line information for all exceptions that have an attribute print_file_and_line, not just SyntaxErrors. This fixes the bug that no proper line number is given for bad \x escapes. @@ -21,6 +27,12 @@ Library arbitrary shell code can't be executed because a bogus URL was passed in. +Windows + +- file.truncate([newsize]) now works on Windows for all newsize values. + It used to fail if newsize didn't fit in 32 bits, reflecting a + limitation of MS _chsize (which is no longer used). + What's New in Python 2.2 final? Release date: 21-Dec-2001 =============================== 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 |