summaryrefslogtreecommitdiffstats
path: root/Objects/fileobject.c
diff options
context:
space:
mode:
authorTrent Mick <trentm@activestate.com>2000-08-11 19:02:59 (GMT)
committerTrent Mick <trentm@activestate.com>2000-08-11 19:02:59 (GMT)
commitf29f47b38beae54db959d0dd2f0800d5dd3fc174 (patch)
tree72e00382e13f07c3299c36e851b5c766a3ef8783 /Objects/fileobject.c
parent7932ed0ac4fb3db990ebffce0d281865d680a10e (diff)
downloadcpython-f29f47b38beae54db959d0dd2f0800d5dd3fc174.zip
cpython-f29f47b38beae54db959d0dd2f0800d5dd3fc174.tar.gz
cpython-f29f47b38beae54db959d0dd2f0800d5dd3fc174.tar.bz2
Add largefile support for Linux64 and WIn64. Add test_largefile and some minor
change to regrtest.py to allow optional running of test_largefile ('cause it's slow on Win64). This closes patches: http://sourceforge.net/patch/index.php?func=detailpatch&patch_id=100510&group_id=5470 and http://sourceforge.net/patch/index.php?func=detailpatch&patch_id=100511&group_id=5470
Diffstat (limited to 'Objects/fileobject.c')
-rw-r--r--Objects/fileobject.c182
1 files changed, 145 insertions, 37 deletions
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 3458f8e..dd2ede0 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -42,8 +42,8 @@ redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#endif
#ifdef MS_WIN32
-#define ftruncate _chsize
#define fileno _fileno
+/* can (almost fully) duplicate with _chsize, see file_truncate */
#define HAVE_FTRUNCATE
#endif
@@ -64,6 +64,12 @@ redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#include <errno.h>
#endif
+/* define the appropriate 64-bit capable tell() function */
+#ifdef MS_WIN64
+# define TELL64 _telli64
+#endif
+
+
typedef struct {
PyObject_HEAD
FILE *f_fp;
@@ -239,12 +245,87 @@ file_close(PyFileObject *f, PyObject *args)
return Py_None;
}
+
+/* a portable fseek() function
+ return 0 on success, non-zero on failure (with errno set) */
+int
+_portable_fseek(fp, offset, whence)
+ FILE* fp;
+#if defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_OFF_T < 8 && SIZEOF_FPOS_T >= 8
+ fpos_t offset;
+#else
+ off_t offset;
+#endif
+ int whence;
+{
+#if defined(HAVE_FSEEKO)
+ return fseeko(fp, offset, whence);
+#elif defined(HAVE_FSEEK64)
+ return fseek64(fp, offset, whence);
+#elif defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_FPOS_T >= 8
+ /* lacking a 64-bit capable fseek() (as Win64 does) use a 64-bit capable
+ fsetpos() and tell() to implement fseek()*/
+ fpos_t pos;
+ switch (whence) {
+ case SEEK_CUR:
+ if (fgetpos(fp, &pos) != 0)
+ return -1;
+ offset += pos;
+ break;
+ case SEEK_END:
+ /* do a "no-op" seek first to sync the buffering so that
+ the low-level tell() can be used correctly */
+ if (fseek(fp, 0, SEEK_END) != 0)
+ return -1;
+ if ((pos = TELL64(fileno(fp))) == -1L)
+ return -1;
+ offset += pos;
+ break;
+ /* case SEEK_SET: break; */
+ }
+ return fsetpos(fp, &offset);
+#else
+ return fseek(fp, offset, whence);
+#endif
+}
+
+
+/* a portable ftell() function
+ Return -1 on failure with errno set appropriately, current file
+ position on success */
+#if defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_OFF_T < 8 && SIZEOF_FPOS_T >= 8
+fpos_t
+#else
+off_t
+#endif
+_portable_ftell(fp)
+ FILE* fp;
+{
+#if defined(HAVE_FTELLO) && defined(HAVE_LARGEFILE_SUPPORT)
+ return ftello(fp);
+#elif defined(HAVE_FTELL64) && defined(HAVE_LARGEFILE_SUPPORT)
+ return ftell64(fp);
+#elif SIZEOF_FPOS_T >= 8 && defined(HAVE_LARGEFILE_SUPPORT)
+ fpos_t pos;
+ if (fgetpos(fp, &pos) != 0)
+ return -1;
+ return pos;
+#else
+ return ftell(fp);
+#endif
+}
+
+
static PyObject *
file_seek(PyFileObject *f, PyObject *args)
{
int whence;
int ret;
+#if defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_OFF_T < 8 && SIZEOF_FPOS_T >= 8
+ fpos_t offset, pos;
+#else
off_t offset;
+#endif /* !MS_WIN64 */
PyObject *offobj;
if (f->f_fp == NULL)
@@ -260,16 +341,12 @@ file_seek(PyFileObject *f, PyObject *args)
#endif
if (PyErr_Occurred())
return NULL;
+
Py_BEGIN_ALLOW_THREADS
errno = 0;
-#if defined(HAVE_FSEEKO)
- ret = fseeko(f->f_fp, offset, whence);
-#elif defined(HAVE_FSEEK64)
- ret = fseek64(f->f_fp, offset, whence);
-#else
- ret = fseek(f->f_fp, offset, whence);
-#endif
+ ret = _portable_fseek(f->f_fp, offset, whence);
Py_END_ALLOW_THREADS
+
if (ret != 0) {
PyErr_SetFromErrno(PyExc_IOError);
clearerr(f->f_fp);
@@ -279,12 +356,17 @@ file_seek(PyFileObject *f, PyObject *args)
return Py_None;
}
+
#ifdef HAVE_FTRUNCATE
static PyObject *
file_truncate(PyFileObject *f, PyObject *args)
{
int ret;
+#if defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_OFF_T < 8 && SIZEOF_FPOS_T >= 8
+ fpos_t newsize;
+#else
off_t newsize;
+#endif
PyObject *newsizeobj;
if (f->f_fp == NULL)
@@ -306,13 +388,7 @@ file_truncate(PyFileObject *f, PyObject *args)
/* Default to current position*/
Py_BEGIN_ALLOW_THREADS
errno = 0;
-#if defined(HAVE_FTELLO) && defined(HAVE_LARGEFILE_SUPPORT)
- newsize = ftello(f->f_fp);
-#elif defined(HAVE_FTELL64) && defined(HAVE_LARGEFILE_SUPPORT)
- newsize = ftell64(f->f_fp);
-#else
- newsize = ftell(f->f_fp);
-#endif
+ newsize = _portable_ftell(f->f_fp);
Py_END_ALLOW_THREADS
if (newsize == -1) {
PyErr_SetFromErrno(PyExc_IOError);
@@ -324,49 +400,66 @@ file_truncate(PyFileObject *f, PyObject *args)
errno = 0;
ret = fflush(f->f_fp);
Py_END_ALLOW_THREADS
- if (ret == 0) {
- Py_BEGIN_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 = ftruncate(fileno(f->f_fp), newsize);
+ ret = _chsize(fileno(f->f_fp), newsize);
Py_END_ALLOW_THREADS
+ if (ret != 0) goto onioerror;
}
- if (ret != 0) {
- PyErr_SetFromErrno(PyExc_IOError);
- clearerr(f->f_fp);
- return NULL;
- }
+#else
+ Py_BEGIN_ALLOW_THREADS
+ errno = 0;
+ ret = ftruncate(fileno(f->f_fp), newsize);
+ Py_END_ALLOW_THREADS
+ if (ret != 0) goto onioerror;
+#endif /* !MS_WIN32 */
+
Py_INCREF(Py_None);
return Py_None;
+
+onioerror:
+ PyErr_SetFromErrno(PyExc_IOError);
+ clearerr(f->f_fp);
+ return NULL;
}
#endif /* HAVE_FTRUNCATE */
static PyObject *
file_tell(PyFileObject *f, PyObject *args)
{
- off_t offset;
+#if defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_OFF_T < 8 && SIZEOF_FPOS_T >= 8
+ fpos_t pos;
+#else
+ off_t pos;
+#endif
+
if (f->f_fp == NULL)
return err_closed();
if (!PyArg_NoArgs(args))
return NULL;
Py_BEGIN_ALLOW_THREADS
errno = 0;
-#if defined(HAVE_FTELLO) && defined(HAVE_LARGEFILE_SUPPORT)
- offset = ftello(f->f_fp);
-#elif defined(HAVE_FTELL64) && defined(HAVE_LARGEFILE_SUPPORT)
- offset = ftell64(f->f_fp);
-#else
- offset = ftell(f->f_fp);
-#endif
+ pos = _portable_ftell(f->f_fp);
Py_END_ALLOW_THREADS
- if (offset == -1) {
+ if (pos == -1) {
PyErr_SetFromErrno(PyExc_IOError);
clearerr(f->f_fp);
return NULL;
}
#if !defined(HAVE_LARGEFILE_SUPPORT)
- return PyInt_FromLong(offset);
+ return PyInt_FromLong(pos);
#else
- return PyLong_FromLongLong(offset);
+ return PyLong_FromLongLong(pos);
#endif
}
@@ -482,6 +575,11 @@ file_read(PyFileObject *f, PyObject *args)
buffersize = new_buffersize(f, (size_t)0);
else
buffersize = bytesrequested;
+ if (buffersize > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "requested number of bytes is more than a Python string can hold");
+ return NULL;
+ }
v = PyString_FromStringAndSize((char *)NULL, buffersize);
if (v == NULL)
return NULL;
@@ -518,7 +616,7 @@ static PyObject *
file_readinto(PyFileObject *f, PyObject *args)
{
char *ptr;
- int ntodo, ndone, nnow;
+ size_t ntodo, ndone, nnow;
if (f->f_fp == NULL)
return err_closed();
@@ -540,7 +638,7 @@ file_readinto(PyFileObject *f, PyObject *args)
ndone += nnow;
ntodo -= nnow;
}
- return PyInt_FromLong(ndone);
+ return PyInt_FromLong((long)ndone);
}
@@ -557,7 +655,7 @@ get_line(PyFileObject *f, int n)
register FILE *fp;
register int c;
register char *buf, *end;
- int n1, n2;
+ size_t n1, n2;
PyObject *v;
fp = f->f_fp;
@@ -596,6 +694,11 @@ get_line(PyFileObject *f, int n)
break;
n1 = n2;
n2 += 1000;
+ if (n2 > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "line is longer than a Python string can hold");
+ return NULL;
+ }
Py_BLOCK_THREADS
if (_PyString_Resize(&v, n2) < 0)
return NULL;
@@ -735,6 +838,11 @@ file_readlines(PyFileObject *f, PyObject *args)
/* Need a larger buffer to fit this line */
nfilled += nread;
buffersize *= 2;
+ if (buffersize > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "line is too long for a Python string");
+ goto error;
+ }
if (big_buffer == NULL) {
/* Create the big buffer */
big_buffer = PyString_FromStringAndSize(