[Python-checkins] CVS: python/dist/src/Objects fileobject.c,2.144,2.145

Tim Peters tim_one@users.sourceforge.net
Sun, 10 Mar 2002 16:24:02 -0800


Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv6297/python/Objects

Modified Files:
	fileobject.c 
Log Message:
file_truncate():  provide full "large file" support on Windows, by
dropping MS's inadequate _chsize() function.  This was inspired by
SF patch 498109 ("fileobject truncate support for win32"), which I
rejected.

libstdtypes.tex:  Someone who knows should update the availability
blurb.  For example, if it's available on Linux, it would be good to
say so.

test_largefile:  Uncommented the file.truncate() tests, and reworked to
do more.  The old comment about "permission errors" in the truncation
tests under Windows was almost certainly due to that the file wasn't open
for *write* access at this point, so of course MS wouldn't let you
truncate it.  I'd be appalled if a Unixish system did.

CAUTION:  Someone should run this test on Linux (etc) too.  The
truncation part was commented out before.  Note that test_largefile isn't
run by default.


Index: fileobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/fileobject.c,v
retrieving revision 2.144
retrieving revision 2.145
diff -C2 -d -r2.144 -r2.145
*** fileobject.c	26 Feb 2002 11:36:35 -0000	2.144
--- fileobject.c	11 Mar 2002 00:24:00 -0000	2.145
***************
*** 11,16 ****
  #ifdef MS_WIN32
  #define fileno _fileno
! /* can (almost fully) duplicate with _chsize, see file_truncate */
  #define HAVE_FTRUNCATE
  #endif
  
--- 11,18 ----
  #ifdef MS_WIN32
  #define fileno _fileno
! /* can simulate truncate with Win32 API functions; see file_truncate */
  #define HAVE_FTRUNCATE
+ #define WINDOWS_LEAN_AND_MEAN
+ #include <windows.h>
  #endif
  
***************
*** 380,383 ****
--- 382,388 ----
  	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)
***************
*** 390,424 ****
  		if (PyErr_Occurred())
  			return NULL;
! 	} 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;
! 		}
  	}
  	Py_BEGIN_ALLOW_THREADS
  	errno = 0;
  	ret = fflush(f->f_fp);
  	Py_END_ALLOW_THREADS
! 	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 {
! 		Py_BEGIN_ALLOW_THREADS
  		errno = 0;
! 		ret = _chsize(fileno(f->f_fp), (long)newsize);
! 		Py_END_ALLOW_THREADS
! 		if (ret != 0) goto onioerror;
  	}
  #else
--- 395,459 ----
  		if (PyErr_Occurred())
  			return NULL;
! 	}
! 	else {
! 		/* Default to current position. */
  		Py_BEGIN_ALLOW_THREADS
  		errno = 0;
  		newsize = _portable_ftell(f->f_fp);
  		Py_END_ALLOW_THREADS
! 		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;
  
  #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. */
! 	{
! 		Py_off_t currentEOF;	/* actual size */
! 		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;
! 			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;
! 		}
! 
  	}
  #else