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

@ -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,32 +415,36 @@ 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. */
/* current <- current file postion. */
if (newsizeobj == NULL)
current = newsize;
else {
Py_BEGIN_ALLOW_THREADS
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)
current = _portable_ftell(f->f_fp);
Py_END_ALLOW_THREADS
if (current == -1)
goto onioerror;
}
if (newsize > currentEOF)
newsize = currentEOF; /* never grow the file */
/* Move to newsize, and truncate the file there. */
if (newsize != currentEOF) {
/* Move to newsize. */
if (current != newsize) {
Py_BEGIN_ALLOW_THREADS
errno = 0;
if (_portable_fseek(f->f_fp, newsize, SEEK_SET) != 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));
@ -453,8 +457,17 @@ file_truncate(PyFileObject *f, PyObject *args)
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