Change Windows file.truncate() to (a) restore the original file position,

and (b) stop trying to prevent file growth.

Beef up the file.truncate() docs.

Change test_largefile.py to stop assuming that f.truncate() moves the
file pointer to the truncation point, and to verify instead that it leaves
the file position alone.  Remove the test for what happens when a
specified size exceeds the original file size (it's ill-defined, according
to the Single Unix Spec).
This commit is contained in:
Tim Peters 2002-03-12 03:04:44 +00:00
parent 9d142adfce
commit 8f01b680c8
3 changed files with 75 additions and 51 deletions

View File

@ -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,9 +1152,14 @@ 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.
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}

View File

@ -133,24 +133,30 @@ if hasattr(f, 'truncate'):
print 'try truncate'
f = open(name, 'r+b')
f.seek(0, 2)
expect(f.tell(), size+1)
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)
# Ensure that truncate(bigger than true size) doesn't grow the file.
f.truncate(size)
expect(f.tell(), newsize)
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(0)
f.seek(42)
f.truncate(newsize)
expect(f.tell(), 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.truncate(1)
f.seek(0)
expect(len(f.read()), 1)
f.truncate(1)
expect(f.tell(), 0) # else pointer moved
expect(len(f.read()), 1) # else wasn't truncated
f.close()
os.unlink(name)

View File

@ -415,46 +415,59 @@ file_truncate(PyFileObject *f, PyObject *args)
#ifdef MS_WIN32
/* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
so don't even try using it. truncate() should never grow the
file, but MS SetEndOfFile will grow a file, so we need to
compare the specified newsize to the actual size. Some
optimization could be done here when newsizeobj is NULL. */
so don't even try using it. */
{
Py_off_t currentEOF; /* actual size */
Py_off_t current; /* current file position */
HANDLE hFile;
int error;
/* First move to EOF, and set currentEOF to the size. */
errno = 0;
if (_portable_fseek(f->f_fp, 0, SEEK_END) != 0)
goto onioerror;
errno = 0;
currentEOF = _portable_ftell(f->f_fp);
if (currentEOF == -1)
goto onioerror;
if (newsize > currentEOF)
newsize = currentEOF; /* never grow the file */
/* Move to newsize, and truncate the file there. */
if (newsize != currentEOF) {
errno = 0;
if (_portable_fseek(f->f_fp, newsize, SEEK_SET) != 0)
goto onioerror;
/* current <- current file postion. */
if (newsizeobj == NULL)
current = newsize;
else {
Py_BEGIN_ALLOW_THREADS
errno = 0;
hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp));
error = hFile == (HANDLE)-1;
if (!error) {
error = SetEndOfFile(hFile) == 0;
if (error)
errno = EACCES;
}
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;
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 (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