summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael W. Hudson <mwh@python.net>2002-03-16 18:19:33 (GMT)
committerMichael W. Hudson <mwh@python.net>2002-03-16 18:19:33 (GMT)
commitfe69139f7e960c52aab54e2b6b1026ced68024d4 (patch)
tree802fdfb9b3913f6d0b5b308334b6e6d76775a5e6
parent13510e7afb849e7b934fdc946ca38738ed4ea4c4 (diff)
downloadcpython-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.tex34
-rw-r--r--Lib/test/test_largefile.py45
-rw-r--r--Misc/NEWS12
-rw-r--r--Objects/fileobject.c84
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)
diff --git a/Misc/NEWS b/Misc/NEWS
index d88c266..3f941c4 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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