2487 lines · 62.3 KB · C
RawDownload
/* File object implementation */ #define PY_SSIZE_T_CLEAN#include "Python.h"#include "structmember.h" #ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif /* HAVE_SYS_TYPES_H */ #ifdef MS_WINDOWS#define fileno _fileno/* can simulate truncate with Win32 API functions; see file_truncate */#define HAVE_FTRUNCATE#define WIN32_LEAN_AND_MEAN#include <windows.h>#endif #ifdef _MSC_VER/* Need GetVersion to see if on NT so safe to use _wfopen */#define WIN32_LEAN_AND_MEAN#include <windows.h>#endif /* _MSC_VER */ #if defined(PYOS_OS2) && defined(PYCC_GCC)#include <io.h>#endif #define BUF(v) PyString_AS_STRING((PyStringObject *)v) #ifndef DONT_HAVE_ERRNO_H#include <errno.h>#endif #ifdef HAVE_GETC_UNLOCKED#define GETC(f) getc_unlocked(f)#define FLOCKFILE(f) flockfile(f)#define FUNLOCKFILE(f) funlockfile(f)#else#define GETC(f) getc(f)#define FLOCKFILE(f)#define FUNLOCKFILE(f)#endif /* Bits in f_newlinetypes */#define NEWLINE_UNKNOWN	0	/* No newline seen, yet */#define NEWLINE_CR 1		/* \r newline seen */#define NEWLINE_LF 2		/* \n newline seen */#define NEWLINE_CRLF 4		/* \r\n newline seen */ #ifdef __cplusplusextern "C" {#endif FILE *PyFile_AsFile(PyObject *f){	if (f == NULL || !PyFile_Check(f))		return NULL;	else		return ((PyFileObject *)f)->f_fp;} PyObject *PyFile_Name(PyObject *f){	if (f == NULL || !PyFile_Check(f))		return NULL;	else		return ((PyFileObject *)f)->f_name;} /* On Unix, fopen will succeed for directories.   In Python, there should be no file objects referring to   directories, so we need a check.  */ static PyFileObject*dircheck(PyFileObject* f){#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)	struct stat buf;	if (f->f_fp == NULL)		return f;	if (fstat(fileno(f->f_fp), &buf) == 0 &&	    S_ISDIR(buf.st_mode)) {#ifdef HAVE_STRERROR		char *msg = strerror(EISDIR);#else		char *msg = "Is a directory";#endif		PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(is)",						      EISDIR, msg);		PyErr_SetObject(PyExc_IOError, exc);		Py_XDECREF(exc);		return NULL;	}#endif	return f;}  static PyObject *fill_file_fields(PyFileObject *f, FILE *fp, PyObject *name, char *mode,		 int (*close)(FILE *)){	assert(name != NULL);	assert(f != NULL);	assert(PyFile_Check(f));	assert(f->f_fp == NULL); 	Py_DECREF(f->f_name);	Py_DECREF(f->f_mode);	Py_DECREF(f->f_encoding);         Py_INCREF(name);        f->f_name = name; 	f->f_mode = PyString_FromString(mode); 	f->f_close = close;	f->f_softspace = 0;	f->f_binary = strchr(mode,'b') != NULL;	f->f_buf = NULL;	f->f_univ_newline = (strchr(mode, 'U') != NULL);	f->f_newlinetypes = NEWLINE_UNKNOWN;	f->f_skipnextlf = 0;	Py_INCREF(Py_None);	f->f_encoding = Py_None; 	if (f->f_mode == NULL)		return NULL;	f->f_fp = fp;        f = dircheck(f);	return (PyObject *) f;} /* check for known incorrect mode strings - problem is, platforms are   free to accept any mode characters they like and are supposed to   ignore stuff they don't understand... write or append mode with   universal newline support is expressly forbidden by PEP 278.   Additionally, remove the 'U' from the mode string as platforms   won't know what it is. *//* zero return is kewl - one is un-kewl */static intsanitize_the_mode(char *mode){	char *upos;	size_t len = strlen(mode); 	if (!len) {		PyErr_SetString(PyExc_ValueError, "empty mode string");		return 1;	} 	upos = strchr(mode, 'U');	if (upos) {		memmove(upos, upos+1, len-(upos-mode)); /* incl null char */ 		if (mode[0] == 'w' || mode[0] == 'a') {			PyErr_Format(PyExc_ValueError, "universal newline "			             "mode can only be used with modes "				     "starting with 'r'");			return 1;		} 		if (mode[0] != 'r') {			memmove(mode+1, mode, strlen(mode)+1);			mode[0] = 'r';		} 		if (!strchr(mode, 'b')) {			memmove(mode+2, mode+1, strlen(mode));			mode[1] = 'b';		}	} else if (mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a') {		PyErr_Format(PyExc_ValueError, "mode string must begin with "	        	    "one of 'r', 'w', 'a' or 'U', not '%.200s'", mode);		return 1;	} 	return 0;} static PyObject *open_the_file(PyFileObject *f, char *name, char *mode){	char *newmode;	assert(f != NULL);	assert(PyFile_Check(f));#ifdef MS_WINDOWS	/* windows ignores the passed name in order to support Unicode */	assert(f->f_name != NULL);#else	assert(name != NULL);#endif	assert(mode != NULL);	assert(f->f_fp == NULL); 	/* probably need to replace 'U' by 'rb' */	newmode = PyMem_MALLOC(strlen(mode) + 3);	if (!newmode) {		PyErr_NoMemory();		return NULL;	}	strcpy(newmode, mode); 	if (sanitize_the_mode(newmode)) {		f = NULL;		goto cleanup;	} 	/* rexec.py can't stop a user from getting the file() constructor --	   all they have to do is get *any* file object f, and then do	   type(f).  Here we prevent them from doing damage with it. */	if (PyEval_GetRestricted()) {		PyErr_SetString(PyExc_IOError,		"file() constructor not accessible in restricted mode");		f = NULL;		goto cleanup;	}	errno = 0; #ifdef MS_WINDOWS	if (PyUnicode_Check(f->f_name)) {		PyObject *wmode;		wmode = PyUnicode_DecodeASCII(newmode, strlen(newmode), NULL);		if (f->f_name && wmode) {			Py_BEGIN_ALLOW_THREADS			/* PyUnicode_AS_UNICODE OK without thread			   lock as it is a simple dereference. */			f->f_fp = _wfopen(PyUnicode_AS_UNICODE(f->f_name),					  PyUnicode_AS_UNICODE(wmode));			Py_END_ALLOW_THREADS		}		Py_XDECREF(wmode);	}#endif	if (NULL == f->f_fp && NULL != name) {		Py_BEGIN_ALLOW_THREADS		f->f_fp = fopen(name, newmode);		Py_END_ALLOW_THREADS	} 	if (f->f_fp == NULL) {#if defined  _MSC_VER && (_MSC_VER < 1400 || !defined(__STDC_SECURE_LIB__))		/* MSVC 6 (Microsoft) leaves errno at 0 for bad mode strings,		 * across all Windows flavors.  When it sets EINVAL varies		 * across Windows flavors, the exact conditions aren't		 * documented, and the answer lies in the OS's implementation		 * of Win32's CreateFile function (whose source is secret).		 * Seems the best we can do is map EINVAL to ENOENT.		 * Starting with Visual Studio .NET 2005, EINVAL is correctly		 * set by our CRT error handler (set in exceptions.c.)		 */		if (errno == 0)	/* bad mode string */			errno = EINVAL;		else if (errno == EINVAL) /* unknown, but not a mode string */			errno = ENOENT;#endif		if (errno == EINVAL)			PyErr_Format(PyExc_IOError, "invalid mode: %s",				     mode);		else			PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, f->f_name);		f = NULL;	}	if (f != NULL)		f = dircheck(f); cleanup:	PyMem_FREE(newmode); 	return (PyObject *)f;} PyObject *PyFile_FromFile(FILE *fp, char *name, char *mode, int (*close)(FILE *)){	PyFileObject *f = (PyFileObject *)PyFile_Type.tp_new(&PyFile_Type,							     NULL, NULL);	if (f != NULL) {		PyObject *o_name = PyString_FromString(name);		if (o_name == NULL)			return NULL;		if (fill_file_fields(f, fp, o_name, mode, close) == NULL) {			Py_DECREF(f);			f = NULL;		}                Py_DECREF(o_name);	}	return (PyObject *) f;} PyObject *PyFile_FromString(char *name, char *mode){	extern int fclose(FILE *);	PyFileObject *f; 	f = (PyFileObject *)PyFile_FromFile((FILE *)NULL, name, mode, fclose);	if (f != NULL) {		if (open_the_file(f, name, mode) == NULL) {			Py_DECREF(f);			f = NULL;		}	}	return (PyObject *)f;} voidPyFile_SetBufSize(PyObject *f, int bufsize){	PyFileObject *file = (PyFileObject *)f;	if (bufsize >= 0) {		int type;		switch (bufsize) {		case 0:			type = _IONBF;			break;#ifdef HAVE_SETVBUF		case 1:			type = _IOLBF;			bufsize = BUFSIZ;			break;#endif		default:			type = _IOFBF;#ifndef HAVE_SETVBUF			bufsize = BUFSIZ;#endif			break;		}		fflush(file->f_fp);		if (type == _IONBF) {			PyMem_Free(file->f_setbuf);			file->f_setbuf = NULL;		} else {			file->f_setbuf = (char *)PyMem_Realloc(file->f_setbuf,                                                                 bufsize);		}#ifdef HAVE_SETVBUF		setvbuf(file->f_fp, file->f_setbuf, type, bufsize);#else /* !HAVE_SETVBUF */		setbuf(file->f_fp, file->f_setbuf);#endif /* !HAVE_SETVBUF */	}} /* Set the encoding used to output Unicode strings.   Returh 1 on success, 0 on failure. */ intPyFile_SetEncoding(PyObject *f, const char *enc){	PyFileObject *file = (PyFileObject*)f;	PyObject *str = PyString_FromString(enc); 	assert(PyFile_Check(f));	if (!str)		return 0;	Py_DECREF(file->f_encoding);	file->f_encoding = str;	return 1;} static PyObject *err_closed(void){	PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");	return NULL;} /* Refuse regular file I/O if there's data in the iteration-buffer. * Mixing them would cause data to arrive out of order, as the read* * methods don't use the iteration buffer. */static PyObject *err_iterbuffered(void){	PyErr_SetString(PyExc_ValueError,		"Mixing iteration and read methods would lose data");	return NULL;} static void drop_readahead(PyFileObject *); /* Methods */ static voidfile_dealloc(PyFileObject *f){	int sts = 0;	if (f->weakreflist != NULL)		PyObject_ClearWeakRefs((PyObject *) f);	if (f->f_fp != NULL && f->f_close != NULL) {		Py_BEGIN_ALLOW_THREADS		sts = (*f->f_close)(f->f_fp);		Py_END_ALLOW_THREADS		if (sts == EOF) #ifdef HAVE_STRERROR			PySys_WriteStderr("close failed: [Errno %d] %s\n", errno, strerror(errno)); #else			PySys_WriteStderr("close failed: [Errno %d]\n", errno); #endif	}	PyMem_Free(f->f_setbuf);	Py_XDECREF(f->f_name);	Py_XDECREF(f->f_mode);	Py_XDECREF(f->f_encoding);	drop_readahead(f);	f->ob_type->tp_free((PyObject *)f);} static PyObject *file_repr(PyFileObject *f){	if (PyUnicode_Check(f->f_name)) {#ifdef Py_USING_UNICODE		PyObject *ret = NULL;		PyObject *name = PyUnicode_AsUnicodeEscapeString(f->f_name);		const char *name_str = name ? PyString_AsString(name) : "?";		ret = PyString_FromFormat("<%s file u'%s', mode '%s' at %p>",				   f->f_fp == NULL ? "closed" : "open",				   name_str,				   PyString_AsString(f->f_mode),				   f);		Py_XDECREF(name);		return ret;#endif	} else {		return PyString_FromFormat("<%s file '%s', mode '%s' at %p>",				   f->f_fp == NULL ? "closed" : "open",				   PyString_AsString(f->f_name),				   PyString_AsString(f->f_mode),				   f);	}} static PyObject *file_close(PyFileObject *f){	int sts = 0;	if (f->f_fp != NULL) {		if (f->f_close != NULL) {			Py_BEGIN_ALLOW_THREADS			errno = 0;			sts = (*f->f_close)(f->f_fp);			Py_END_ALLOW_THREADS		}		f->f_fp = NULL;	}	PyMem_Free(f->f_setbuf);	f->f_setbuf = NULL;	if (sts == EOF)		return PyErr_SetFromErrno(PyExc_IOError);	if (sts != 0)		return PyInt_FromLong((long)sts);	Py_INCREF(Py_None);	return Py_None;}  /* Our very own off_t-like type, 64-bit if possible */#if !defined(HAVE_LARGEFILE_SUPPORT)typedef off_t Py_off_t;#elif SIZEOF_OFF_T >= 8typedef off_t Py_off_t;#elif SIZEOF_FPOS_T >= 8typedef fpos_t Py_off_t;#else#error "Large file support, but neither off_t nor fpos_t is large enough."#endif  /* a portable fseek() function   return 0 on success, non-zero on failure (with errno set) */static int_portable_fseek(FILE *fp, Py_off_t offset, int whence){#if !defined(HAVE_LARGEFILE_SUPPORT)	return fseek(fp, offset, whence);#elif defined(HAVE_FSEEKO) && SIZEOF_OFF_T >= 8	return fseeko(fp, offset, whence);#elif defined(HAVE_FSEEK64)	return fseek64(fp, offset, whence);#elif defined(__BEOS__)	return _fseek(fp, offset, whence);#elif SIZEOF_FPOS_T >= 8	/* lacking a 64-bit capable fseek(), use a 64-bit capable fsetpos()	   and fgetpos() to implement fseek()*/	fpos_t pos;	switch (whence) {	case SEEK_END:#ifdef MS_WINDOWS		fflush(fp);		if (_lseeki64(fileno(fp), 0, 2) == -1)			return -1;#else		if (fseek(fp, 0, SEEK_END) != 0)			return -1;#endif

Lines 1–500 of 2487.