symbian-qemu-0.9.1-12/python-2.6.1/Modules/_fileio.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /* Author: Daniel Stutzbach */
       
     2 
       
     3 #define PY_SSIZE_T_CLEAN
       
     4 #include "Python.h"
       
     5 #include <sys/types.h>
       
     6 #include <sys/stat.h>
       
     7 #include <fcntl.h>
       
     8 #include <stddef.h> /* For offsetof */
       
     9 
       
    10 /*
       
    11  * Known likely problems:
       
    12  *
       
    13  * - Files larger then 2**32-1
       
    14  * - Files with unicode filenames
       
    15  * - Passing numbers greater than 2**32-1 when an integer is expected
       
    16  * - Making it work on Windows and other oddball platforms
       
    17  *
       
    18  * To Do:
       
    19  *
       
    20  * - autoconfify header file inclusion
       
    21  */
       
    22 
       
    23 #ifdef MS_WINDOWS
       
    24 /* can simulate truncate with Win32 API functions; see file_truncate */
       
    25 #define HAVE_FTRUNCATE
       
    26 #define WIN32_LEAN_AND_MEAN
       
    27 #include <windows.h>
       
    28 #endif
       
    29 
       
    30 typedef struct {
       
    31 	PyObject_HEAD
       
    32 	int fd;
       
    33 	unsigned readable : 1;
       
    34 	unsigned writable : 1;
       
    35 	int seekable : 2; /* -1 means unknown */
       
    36 	int closefd : 1;
       
    37 	PyObject *weakreflist;
       
    38 } PyFileIOObject;
       
    39 
       
    40 PyTypeObject PyFileIO_Type;
       
    41 
       
    42 #define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
       
    43 
       
    44 /* Returns 0 on success, errno (which is < 0) on failure. */
       
    45 static int
       
    46 internal_close(PyFileIOObject *self)
       
    47 {
       
    48 	int save_errno = 0;
       
    49 	if (self->fd >= 0) {
       
    50 		int fd = self->fd;
       
    51 		self->fd = -1;
       
    52 		Py_BEGIN_ALLOW_THREADS
       
    53 		if (close(fd) < 0)
       
    54 			save_errno = errno;
       
    55 		Py_END_ALLOW_THREADS
       
    56 	}
       
    57 	return save_errno;
       
    58 }
       
    59 
       
    60 static PyObject *
       
    61 fileio_close(PyFileIOObject *self)
       
    62 {
       
    63 	if (!self->closefd) {
       
    64 		if (PyErr_WarnEx(PyExc_RuntimeWarning,
       
    65 				 "Trying to close unclosable fd!", 3) < 0) {
       
    66 			return NULL;
       
    67 		}
       
    68 		Py_RETURN_NONE;
       
    69 	}
       
    70 	errno = internal_close(self);
       
    71 	if (errno < 0) {
       
    72 		PyErr_SetFromErrno(PyExc_IOError);
       
    73 		return NULL;
       
    74 	}
       
    75 
       
    76 	Py_RETURN_NONE;
       
    77 }
       
    78 
       
    79 static PyObject *
       
    80 fileio_new(PyTypeObject *type, PyObject *args, PyObject *kews)
       
    81 {
       
    82 	PyFileIOObject *self;
       
    83 
       
    84 	assert(type != NULL && type->tp_alloc != NULL);
       
    85 
       
    86 	self = (PyFileIOObject *) type->tp_alloc(type, 0);
       
    87 	if (self != NULL) {
       
    88 		self->fd = -1;
       
    89 		self->readable = 0;
       
    90 		self->writable = 0;
       
    91 		self->seekable = -1;
       
    92 		self->closefd = 1;
       
    93 		self->weakreflist = NULL;
       
    94 	}
       
    95 
       
    96 	return (PyObject *) self;
       
    97 }
       
    98 
       
    99 /* On Unix, open will succeed for directories.
       
   100    In Python, there should be no file objects referring to
       
   101    directories, so we need a check.  */
       
   102 
       
   103 static int
       
   104 dircheck(PyFileIOObject* self)
       
   105 {
       
   106 #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
       
   107 	struct stat buf;
       
   108 	if (self->fd < 0)
       
   109 		return 0;
       
   110 	if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
       
   111 		char *msg = strerror(EISDIR);
       
   112 		PyObject *exc;
       
   113 		internal_close(self);
       
   114 
       
   115 		exc = PyObject_CallFunction(PyExc_IOError, "(is)",
       
   116 					    EISDIR, msg);
       
   117 		PyErr_SetObject(PyExc_IOError, exc);
       
   118 		Py_XDECREF(exc);
       
   119 		return -1;
       
   120 	}
       
   121 #endif
       
   122 	return 0;
       
   123 }
       
   124 
       
   125 
       
   126 static int
       
   127 fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
       
   128 {
       
   129 	PyFileIOObject *self = (PyFileIOObject *) oself;
       
   130 	static char *kwlist[] = {"file", "mode", "closefd", NULL};
       
   131 	char *name = NULL;
       
   132 	char *mode = "r";
       
   133 	char *s;
       
   134 #ifdef MS_WINDOWS
       
   135 	Py_UNICODE *widename = NULL;
       
   136 #endif
       
   137 	int ret = 0;
       
   138 	int rwa = 0, plus = 0, append = 0;
       
   139 	int flags = 0;
       
   140 	int fd = -1;
       
   141 	int closefd = 1;
       
   142 
       
   143 	assert(PyFileIO_Check(oself));
       
   144 	if (self->fd >= 0) {
       
   145 		/* Have to close the existing file first. */
       
   146 		if (internal_close(self) < 0)
       
   147 			return -1;
       
   148 	}
       
   149 
       
   150 	if (PyArg_ParseTupleAndKeywords(args, kwds, "i|si:fileio",
       
   151 					kwlist, &fd, &mode, &closefd)) {
       
   152 		if (fd < 0) {
       
   153 			PyErr_SetString(PyExc_ValueError,
       
   154 					"Negative filedescriptor");
       
   155 			return -1;
       
   156 		}
       
   157 	}
       
   158 	else {
       
   159 		PyErr_Clear();
       
   160 
       
   161 #ifdef Py_WIN_WIDE_FILENAMES
       
   162 	    if (GetVersion() < 0x80000000) {
       
   163 		/* On NT, so wide API available */
       
   164 		PyObject *po;
       
   165 		if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:fileio",
       
   166 						kwlist, &po, &mode, &closefd)
       
   167 						) {
       
   168 			widename = PyUnicode_AS_UNICODE(po);
       
   169 		} else {
       
   170 			/* Drop the argument parsing error as narrow
       
   171 			   strings are also valid. */
       
   172 			PyErr_Clear();
       
   173 		}
       
   174 	    }
       
   175 	    if (widename == NULL)
       
   176 #endif
       
   177 	    {
       
   178 		if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:fileio",
       
   179 						 kwlist,
       
   180 						 Py_FileSystemDefaultEncoding,
       
   181 						 &name, &mode, &closefd))
       
   182 			return -1;
       
   183 	    }
       
   184 	}
       
   185 
       
   186 	s = mode;
       
   187 	while (*s) {
       
   188 		switch (*s++) {
       
   189 		case 'r':
       
   190 			if (rwa) {
       
   191 			bad_mode:
       
   192 				PyErr_SetString(PyExc_ValueError,
       
   193 						"Must have exactly one of read/write/append mode");
       
   194 				goto error;
       
   195 			}
       
   196 			rwa = 1;
       
   197 			self->readable = 1;
       
   198 			break;
       
   199 		case 'w':
       
   200 			if (rwa)
       
   201 				goto bad_mode;
       
   202 			rwa = 1;
       
   203 			self->writable = 1;
       
   204 			flags |= O_CREAT | O_TRUNC;
       
   205 			break;
       
   206 		case 'a':
       
   207 			if (rwa)
       
   208 				goto bad_mode;
       
   209 			rwa = 1;
       
   210 			self->writable = 1;
       
   211 			flags |= O_CREAT;
       
   212 			append = 1;
       
   213 			break;
       
   214 		case '+':
       
   215 			if (plus)
       
   216 				goto bad_mode;
       
   217 			self->readable = self->writable = 1;
       
   218 			plus = 1;
       
   219 			break;
       
   220 		default:
       
   221 			PyErr_Format(PyExc_ValueError,
       
   222 				     "invalid mode: %.200s", mode);
       
   223 			goto error;
       
   224 		}
       
   225 	}
       
   226 
       
   227 	if (!rwa)
       
   228 		goto bad_mode;
       
   229 
       
   230 	if (self->readable && self->writable)
       
   231 		flags |= O_RDWR;
       
   232 	else if (self->readable)
       
   233 		flags |= O_RDONLY;
       
   234 	else
       
   235 		flags |= O_WRONLY;
       
   236 
       
   237 #ifdef O_BINARY
       
   238 	flags |= O_BINARY;
       
   239 #endif
       
   240 
       
   241 #ifdef O_APPEND
       
   242 	if (append)
       
   243 		flags |= O_APPEND;
       
   244 #endif
       
   245 
       
   246 	if (fd >= 0) {
       
   247 		self->fd = fd;
       
   248 		self->closefd = closefd;
       
   249 	}
       
   250 	else {
       
   251 		self->closefd = 1;
       
   252 		if (!closefd) {
       
   253 			PyErr_SetString(PyExc_ValueError,
       
   254                             "Cannot use closefd=False with file name");
       
   255 			goto error;
       
   256 		}
       
   257 
       
   258 		Py_BEGIN_ALLOW_THREADS
       
   259 		errno = 0;
       
   260 #ifdef MS_WINDOWS
       
   261 		if (widename != NULL)
       
   262 			self->fd = _wopen(widename, flags, 0666);
       
   263 		else
       
   264 #endif
       
   265 			self->fd = open(name, flags, 0666);
       
   266 		Py_END_ALLOW_THREADS
       
   267 		if (self->fd < 0) {
       
   268 #ifdef MS_WINDOWS
       
   269 			PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename);
       
   270 #else
       
   271 			PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
       
   272 #endif
       
   273 			goto error;
       
   274 		}
       
   275 		if(dircheck(self) < 0)
       
   276 			goto error;
       
   277 	}
       
   278 
       
   279 	goto done;
       
   280 
       
   281  error:
       
   282 	ret = -1;
       
   283 
       
   284  done:
       
   285 	PyMem_Free(name);
       
   286 	return ret;
       
   287 }
       
   288 
       
   289 static void
       
   290 fileio_dealloc(PyFileIOObject *self)
       
   291 {
       
   292 	if (self->weakreflist != NULL)
       
   293 		PyObject_ClearWeakRefs((PyObject *) self);
       
   294 
       
   295 	if (self->fd >= 0 && self->closefd) {
       
   296 		errno = internal_close(self);
       
   297 		if (errno < 0) {
       
   298 			PySys_WriteStderr("close failed: [Errno %d] %s\n",
       
   299                                           errno, strerror(errno));
       
   300 		}
       
   301 	}
       
   302 
       
   303 	Py_TYPE(self)->tp_free((PyObject *)self);
       
   304 }
       
   305 
       
   306 static PyObject *
       
   307 err_closed(void)
       
   308 {
       
   309 	PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
       
   310 	return NULL;
       
   311 }
       
   312 
       
   313 static PyObject *
       
   314 err_mode(char *action)
       
   315 {
       
   316 	PyErr_Format(PyExc_ValueError, "File not open for %s", action);
       
   317 	return NULL;
       
   318 }
       
   319 
       
   320 static PyObject *
       
   321 fileio_fileno(PyFileIOObject *self)
       
   322 {
       
   323 	if (self->fd < 0)
       
   324 		return err_closed();
       
   325 	return PyInt_FromLong((long) self->fd);
       
   326 }
       
   327 
       
   328 static PyObject *
       
   329 fileio_readable(PyFileIOObject *self)
       
   330 {
       
   331 	if (self->fd < 0)
       
   332 		return err_closed();
       
   333 	return PyBool_FromLong((long) self->readable);
       
   334 }
       
   335 
       
   336 static PyObject *
       
   337 fileio_writable(PyFileIOObject *self)
       
   338 {
       
   339 	if (self->fd < 0)
       
   340 		return err_closed();
       
   341 	return PyBool_FromLong((long) self->writable);
       
   342 }
       
   343 
       
   344 static PyObject *
       
   345 fileio_seekable(PyFileIOObject *self)
       
   346 {
       
   347 	if (self->fd < 0)
       
   348 		return err_closed();
       
   349 	if (self->seekable < 0) {
       
   350 		int ret;
       
   351 		Py_BEGIN_ALLOW_THREADS
       
   352 		ret = lseek(self->fd, 0, SEEK_CUR);
       
   353 		Py_END_ALLOW_THREADS
       
   354 		if (ret < 0)
       
   355 			self->seekable = 0;
       
   356 		else
       
   357 			self->seekable = 1;
       
   358 	}
       
   359 	return PyBool_FromLong((long) self->seekable);
       
   360 }
       
   361 
       
   362 static PyObject *
       
   363 fileio_readinto(PyFileIOObject *self, PyObject *args)
       
   364 {
       
   365 	Py_buffer pbuf;
       
   366 	Py_ssize_t n;
       
   367 
       
   368 	if (self->fd < 0)
       
   369 		return err_closed();
       
   370 	if (!self->readable)
       
   371 		return err_mode("reading");
       
   372 
       
   373 	if (!PyArg_ParseTuple(args, "w*", &pbuf))
       
   374 		return NULL;
       
   375 
       
   376 	Py_BEGIN_ALLOW_THREADS
       
   377 	errno = 0;
       
   378 	n = read(self->fd, pbuf.buf, pbuf.len);
       
   379 	Py_END_ALLOW_THREADS
       
   380 	PyBuffer_Release(&pbuf);
       
   381 	if (n < 0) {
       
   382 		if (errno == EAGAIN)
       
   383 			Py_RETURN_NONE;
       
   384 		PyErr_SetFromErrno(PyExc_IOError);
       
   385 		return NULL;
       
   386 	}
       
   387 
       
   388 	return PyLong_FromSsize_t(n);
       
   389 }
       
   390 
       
   391 #define DEFAULT_BUFFER_SIZE (8*1024)
       
   392 
       
   393 static PyObject *
       
   394 fileio_readall(PyFileIOObject *self)
       
   395 {
       
   396 	PyObject *result;
       
   397 	Py_ssize_t total = 0;
       
   398 	int n;
       
   399 
       
   400 	result = PyString_FromStringAndSize(NULL, DEFAULT_BUFFER_SIZE);
       
   401 	if (result == NULL)
       
   402 		return NULL;
       
   403 
       
   404 	while (1) {
       
   405 		Py_ssize_t newsize = total + DEFAULT_BUFFER_SIZE;
       
   406 		if (PyString_GET_SIZE(result) < newsize) {
       
   407 			if (_PyString_Resize(&result, newsize) < 0) {
       
   408 				if (total == 0) {
       
   409 					Py_DECREF(result);
       
   410 					return NULL;
       
   411 				}
       
   412 				PyErr_Clear();
       
   413 				break;
       
   414 			}
       
   415 		}
       
   416 		Py_BEGIN_ALLOW_THREADS
       
   417 		errno = 0;
       
   418 		n = read(self->fd,
       
   419 			 PyString_AS_STRING(result) + total,
       
   420 			 newsize - total);
       
   421 		Py_END_ALLOW_THREADS
       
   422 		if (n == 0)
       
   423 			break;
       
   424 		if (n < 0) {
       
   425 			if (total > 0)
       
   426 				break;
       
   427 			if (errno == EAGAIN) {
       
   428 				Py_DECREF(result);
       
   429 				Py_RETURN_NONE;
       
   430 			}
       
   431 			Py_DECREF(result);
       
   432 			PyErr_SetFromErrno(PyExc_IOError);
       
   433 			return NULL;
       
   434 		}
       
   435 		total += n;
       
   436 	}
       
   437 
       
   438 	if (PyString_GET_SIZE(result) > total) {
       
   439 		if (_PyString_Resize(&result, total) < 0) {
       
   440 			/* This should never happen, but just in case */
       
   441 			Py_DECREF(result);
       
   442 			return NULL;
       
   443 		}
       
   444 	}
       
   445 	return result;
       
   446 }
       
   447 
       
   448 static PyObject *
       
   449 fileio_read(PyFileIOObject *self, PyObject *args)
       
   450 {
       
   451 	char *ptr;
       
   452 	Py_ssize_t n;
       
   453 	Py_ssize_t size = -1;
       
   454 	PyObject *bytes;
       
   455 
       
   456 	if (self->fd < 0)
       
   457 		return err_closed();
       
   458 	if (!self->readable)
       
   459 		return err_mode("reading");
       
   460 
       
   461 	if (!PyArg_ParseTuple(args, "|n", &size))
       
   462 		return NULL;
       
   463 
       
   464         if (size < 0) {
       
   465 		return fileio_readall(self);
       
   466 	}
       
   467 
       
   468 	bytes = PyString_FromStringAndSize(NULL, size);
       
   469 	if (bytes == NULL)
       
   470 		return NULL;
       
   471 	ptr = PyString_AS_STRING(bytes);
       
   472 
       
   473 	Py_BEGIN_ALLOW_THREADS
       
   474 	errno = 0;
       
   475 	n = read(self->fd, ptr, size);
       
   476 	Py_END_ALLOW_THREADS
       
   477 
       
   478 	if (n < 0) {
       
   479 		if (errno == EAGAIN)
       
   480 			Py_RETURN_NONE;
       
   481 		PyErr_SetFromErrno(PyExc_IOError);
       
   482 		return NULL;
       
   483 	}
       
   484 
       
   485 	if (n != size) {
       
   486 		if (_PyString_Resize(&bytes, n) < 0) {
       
   487 			Py_DECREF(bytes);
       
   488 			return NULL;
       
   489 		}
       
   490 	}
       
   491 
       
   492 	return (PyObject *) bytes;
       
   493 }
       
   494 
       
   495 static PyObject *
       
   496 fileio_write(PyFileIOObject *self, PyObject *args)
       
   497 {
       
   498 	Py_buffer pbuf;
       
   499 	Py_ssize_t n;
       
   500 
       
   501 	if (self->fd < 0)
       
   502 		return err_closed();
       
   503 	if (!self->writable)
       
   504 		return err_mode("writing");
       
   505 
       
   506 	if (!PyArg_ParseTuple(args, "s*", &pbuf))
       
   507 		return NULL;
       
   508 
       
   509 	Py_BEGIN_ALLOW_THREADS
       
   510 	errno = 0;
       
   511 	n = write(self->fd, pbuf.buf, pbuf.len);
       
   512 	Py_END_ALLOW_THREADS
       
   513 
       
   514 	PyBuffer_Release(&pbuf);
       
   515 
       
   516 	if (n < 0) {
       
   517 		if (errno == EAGAIN)
       
   518 			Py_RETURN_NONE;
       
   519 		PyErr_SetFromErrno(PyExc_IOError);
       
   520 		return NULL;
       
   521 	}
       
   522 
       
   523 	return PyLong_FromSsize_t(n);
       
   524 }
       
   525 
       
   526 /* XXX Windows support below is likely incomplete */
       
   527 
       
   528 #if defined(MS_WIN64) || defined(MS_WINDOWS)
       
   529 typedef PY_LONG_LONG Py_off_t;
       
   530 #else
       
   531 typedef off_t Py_off_t;
       
   532 #endif
       
   533 
       
   534 /* Cribbed from posix_lseek() */
       
   535 static PyObject *
       
   536 portable_lseek(int fd, PyObject *posobj, int whence)
       
   537 {
       
   538 	Py_off_t pos, res;
       
   539 
       
   540 #ifdef SEEK_SET
       
   541 	/* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
       
   542 	switch (whence) {
       
   543 #if SEEK_SET != 0
       
   544 	case 0: whence = SEEK_SET; break;
       
   545 #endif
       
   546 #if SEEK_CUR != 1
       
   547 	case 1: whence = SEEK_CUR; break;
       
   548 #endif
       
   549 #if SEEL_END != 2
       
   550 	case 2: whence = SEEK_END; break;
       
   551 #endif
       
   552 	}
       
   553 #endif /* SEEK_SET */
       
   554 
       
   555 	if (posobj == NULL)
       
   556 		pos = 0;
       
   557 	else {
       
   558 		if(PyFloat_Check(posobj)) {
       
   559 			PyErr_SetString(PyExc_TypeError, "an integer is required");
       
   560 			return NULL;
       
   561 		}
       
   562 #if defined(HAVE_LARGEFILE_SUPPORT)
       
   563 		pos = PyLong_AsLongLong(posobj);
       
   564 #else
       
   565 		pos = PyLong_AsLong(posobj);
       
   566 #endif
       
   567 		if (PyErr_Occurred())
       
   568 			return NULL;
       
   569 	}
       
   570 
       
   571 	Py_BEGIN_ALLOW_THREADS
       
   572 #if defined(MS_WIN64) || defined(MS_WINDOWS)
       
   573 	res = _lseeki64(fd, pos, whence);
       
   574 #else
       
   575 	res = lseek(fd, pos, whence);
       
   576 #endif
       
   577 	Py_END_ALLOW_THREADS
       
   578 	if (res < 0)
       
   579 		return PyErr_SetFromErrno(PyExc_IOError);
       
   580 
       
   581 #if defined(HAVE_LARGEFILE_SUPPORT)
       
   582 	return PyLong_FromLongLong(res);
       
   583 #else
       
   584 	return PyLong_FromLong(res);
       
   585 #endif
       
   586 }
       
   587 
       
   588 static PyObject *
       
   589 fileio_seek(PyFileIOObject *self, PyObject *args)
       
   590 {
       
   591 	PyObject *posobj;
       
   592 	int whence = 0;
       
   593 
       
   594 	if (self->fd < 0)
       
   595 		return err_closed();
       
   596 
       
   597 	if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))
       
   598 		return NULL;
       
   599 
       
   600 	return portable_lseek(self->fd, posobj, whence);
       
   601 }
       
   602 
       
   603 static PyObject *
       
   604 fileio_tell(PyFileIOObject *self, PyObject *args)
       
   605 {
       
   606 	if (self->fd < 0)
       
   607 		return err_closed();
       
   608 
       
   609 	return portable_lseek(self->fd, NULL, 1);
       
   610 }
       
   611 
       
   612 #ifdef HAVE_FTRUNCATE
       
   613 static PyObject *
       
   614 fileio_truncate(PyFileIOObject *self, PyObject *args)
       
   615 {
       
   616 	PyObject *posobj = NULL;
       
   617 	Py_off_t pos;
       
   618 	int ret;
       
   619 	int fd;
       
   620 
       
   621 	fd = self->fd;
       
   622 	if (fd < 0)
       
   623 		return err_closed();
       
   624 	if (!self->writable)
       
   625 		return err_mode("writing");
       
   626 
       
   627 	if (!PyArg_ParseTuple(args, "|O", &posobj))
       
   628 		return NULL;
       
   629 
       
   630 	if (posobj == Py_None || posobj == NULL) {
       
   631 		/* Get the current position. */
       
   632                 posobj = portable_lseek(fd, NULL, 1);
       
   633                 if (posobj == NULL)
       
   634 			return NULL;
       
   635         }
       
   636         else {
       
   637 		/* Move to the position to be truncated. */
       
   638                 posobj = portable_lseek(fd, posobj, 0);
       
   639         }
       
   640 
       
   641 #if defined(HAVE_LARGEFILE_SUPPORT)
       
   642 	pos = PyLong_AsLongLong(posobj);
       
   643 #else
       
   644 	pos = PyLong_AsLong(posobj);
       
   645 #endif
       
   646 	if (PyErr_Occurred())
       
   647 		return NULL;
       
   648 
       
   649 #ifdef MS_WINDOWS
       
   650 	/* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
       
   651 	   so don't even try using it. */
       
   652 	{
       
   653 		HANDLE hFile;
       
   654 
       
   655 		/* Truncate.  Note that this may grow the file! */
       
   656 		Py_BEGIN_ALLOW_THREADS
       
   657 		errno = 0;
       
   658 		hFile = (HANDLE)_get_osfhandle(fd);
       
   659 		ret = hFile == (HANDLE)-1;
       
   660 		if (ret == 0) {
       
   661 			ret = SetEndOfFile(hFile) == 0;
       
   662 			if (ret)
       
   663 				errno = EACCES;
       
   664 		}
       
   665 		Py_END_ALLOW_THREADS
       
   666 	}
       
   667 #else
       
   668 	Py_BEGIN_ALLOW_THREADS
       
   669 	errno = 0;
       
   670 	ret = ftruncate(fd, pos);
       
   671 	Py_END_ALLOW_THREADS
       
   672 #endif /* !MS_WINDOWS */
       
   673 
       
   674 	if (ret != 0) {
       
   675 		PyErr_SetFromErrno(PyExc_IOError);
       
   676 		return NULL;
       
   677 	}
       
   678 
       
   679 	return posobj;
       
   680 }
       
   681 #endif
       
   682 
       
   683 static char *
       
   684 mode_string(PyFileIOObject *self)
       
   685 {
       
   686 	if (self->readable) {
       
   687 		if (self->writable)
       
   688 			return "r+";
       
   689 		else
       
   690 			return "r";
       
   691 	}
       
   692 	else
       
   693 		return "w";
       
   694 }
       
   695 
       
   696 static PyObject *
       
   697 fileio_repr(PyFileIOObject *self)
       
   698 {
       
   699         if (self->fd < 0)
       
   700 		return PyString_FromFormat("_fileio._FileIO(-1)");
       
   701 
       
   702 	return PyString_FromFormat("_fileio._FileIO(%d, '%s')",
       
   703 				   self->fd, mode_string(self));
       
   704 }
       
   705 
       
   706 static PyObject *
       
   707 fileio_isatty(PyFileIOObject *self)
       
   708 {
       
   709 	long res;
       
   710 
       
   711 	if (self->fd < 0)
       
   712 		return err_closed();
       
   713 	Py_BEGIN_ALLOW_THREADS
       
   714 	res = isatty(self->fd);
       
   715 	Py_END_ALLOW_THREADS
       
   716 	return PyBool_FromLong(res);
       
   717 }
       
   718 
       
   719 
       
   720 PyDoc_STRVAR(fileio_doc,
       
   721 "file(name: str[, mode: str]) -> file IO object\n"
       
   722 "\n"
       
   723 "Open a file.  The mode can be 'r', 'w' or 'a' for reading (default),\n"
       
   724 "writing or appending.	The file will be created if it doesn't exist\n"
       
   725 "when opened for writing or appending; it will be truncated when\n"
       
   726 "opened for writing.  Add a '+' to the mode to allow simultaneous\n"
       
   727 "reading and writing.");
       
   728 
       
   729 PyDoc_STRVAR(read_doc,
       
   730 "read(size: int) -> bytes.  read at most size bytes, returned as bytes.\n"
       
   731 "\n"
       
   732 "Only makes one system call, so less data may be returned than requested\n"
       
   733 "In non-blocking mode, returns None if no data is available.\n"
       
   734 "On end-of-file, returns ''.");
       
   735 
       
   736 PyDoc_STRVAR(readall_doc,
       
   737 "readall() -> bytes.  read all data from the file, returned as bytes.\n"
       
   738 "\n"
       
   739 "In non-blocking mode, returns as much as is immediately available,\n"
       
   740 "or None if no data is available.  On end-of-file, returns ''.");
       
   741 
       
   742 PyDoc_STRVAR(write_doc,
       
   743 "write(b: bytes) -> int.  Write bytes b to file, return number written.\n"
       
   744 "\n"
       
   745 "Only makes one system call, so not all of the data may be written.\n"
       
   746 "The number of bytes actually written is returned.");
       
   747 
       
   748 PyDoc_STRVAR(fileno_doc,
       
   749 "fileno() -> int. \"file descriptor\".\n"
       
   750 "\n"
       
   751 "This is needed for lower-level file interfaces, such the fcntl module.");
       
   752 
       
   753 PyDoc_STRVAR(seek_doc,
       
   754 "seek(offset: int[, whence: int]) -> None.  Move to new file position.\n"
       
   755 "\n"
       
   756 "Argument offset is a byte count.  Optional argument whence defaults to\n"
       
   757 "0 (offset from start of file, offset should be >= 0); other values are 1\n"
       
   758 "(move relative to current position, positive or negative), and 2 (move\n"
       
   759 "relative to end of file, usually negative, although many platforms allow\n"
       
   760 "seeking beyond the end of a file)."
       
   761 "\n"
       
   762 "Note that not all file objects are seekable.");
       
   763 
       
   764 #ifdef HAVE_FTRUNCATE
       
   765 PyDoc_STRVAR(truncate_doc,
       
   766 "truncate([size: int]) -> None.	 Truncate the file to at most size bytes.\n"
       
   767 "\n"
       
   768 "Size defaults to the current file position, as returned by tell()."
       
   769 "The current file position is changed to the value of size.");
       
   770 #endif
       
   771 
       
   772 PyDoc_STRVAR(tell_doc,
       
   773 "tell() -> int.	 Current file position");
       
   774 
       
   775 PyDoc_STRVAR(readinto_doc,
       
   776 "readinto() -> Undocumented.  Don't use this; it may go away.");
       
   777 
       
   778 PyDoc_STRVAR(close_doc,
       
   779 "close() -> None.  Close the file.\n"
       
   780 "\n"
       
   781 "A closed file cannot be used for further I/O operations.  close() may be\n"
       
   782 "called more than once without error.  Changes the fileno to -1.");
       
   783 
       
   784 PyDoc_STRVAR(isatty_doc,
       
   785 "isatty() -> bool.  True if the file is connected to a tty device.");
       
   786 
       
   787 PyDoc_STRVAR(seekable_doc,
       
   788 "seekable() -> bool.  True if file supports random-access.");
       
   789 
       
   790 PyDoc_STRVAR(readable_doc,
       
   791 "readable() -> bool.  True if file was opened in a read mode.");
       
   792 
       
   793 PyDoc_STRVAR(writable_doc,
       
   794 "writable() -> bool.  True if file was opened in a write mode.");
       
   795 
       
   796 static PyMethodDef fileio_methods[] = {
       
   797 	{"read",     (PyCFunction)fileio_read,	   METH_VARARGS, read_doc},
       
   798 	{"readall",  (PyCFunction)fileio_readall,  METH_NOARGS,  readall_doc},
       
   799 	{"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},
       
   800 	{"write",    (PyCFunction)fileio_write,	   METH_VARARGS, write_doc},
       
   801 	{"seek",     (PyCFunction)fileio_seek,	   METH_VARARGS, seek_doc},
       
   802 	{"tell",     (PyCFunction)fileio_tell,	   METH_VARARGS, tell_doc},
       
   803 #ifdef HAVE_FTRUNCATE
       
   804 	{"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},
       
   805 #endif
       
   806 	{"close",    (PyCFunction)fileio_close,	   METH_NOARGS,	 close_doc},
       
   807 	{"seekable", (PyCFunction)fileio_seekable, METH_NOARGS,	 seekable_doc},
       
   808 	{"readable", (PyCFunction)fileio_readable, METH_NOARGS,	 readable_doc},
       
   809 	{"writable", (PyCFunction)fileio_writable, METH_NOARGS,	 writable_doc},
       
   810 	{"fileno",   (PyCFunction)fileio_fileno,   METH_NOARGS,	 fileno_doc},
       
   811 	{"isatty",   (PyCFunction)fileio_isatty,   METH_NOARGS,	 isatty_doc},
       
   812 	{NULL,	     NULL}	       /* sentinel */
       
   813 };
       
   814 
       
   815 /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
       
   816 
       
   817 static PyObject *
       
   818 get_closed(PyFileIOObject *self, void *closure)
       
   819 {
       
   820 	return PyBool_FromLong((long)(self->fd < 0));
       
   821 }
       
   822 
       
   823 static PyObject *
       
   824 get_mode(PyFileIOObject *self, void *closure)
       
   825 {
       
   826 	return PyString_FromString(mode_string(self));
       
   827 }
       
   828 
       
   829 static PyGetSetDef fileio_getsetlist[] = {
       
   830 	{"closed", (getter)get_closed, NULL, "True if the file is closed"},
       
   831 	{"mode", (getter)get_mode, NULL, "String giving the file mode"},
       
   832 	{0},
       
   833 };
       
   834 
       
   835 PyTypeObject PyFileIO_Type = {
       
   836 	PyVarObject_HEAD_INIT(NULL, 0)
       
   837 	"_FileIO",
       
   838 	sizeof(PyFileIOObject),
       
   839 	0,
       
   840 	(destructor)fileio_dealloc,		/* tp_dealloc */
       
   841 	0,					/* tp_print */
       
   842 	0,					/* tp_getattr */
       
   843 	0,					/* tp_setattr */
       
   844 	0,					/* tp_compare */
       
   845 	(reprfunc)fileio_repr,			/* tp_repr */
       
   846 	0,					/* tp_as_number */
       
   847 	0,					/* tp_as_sequence */
       
   848 	0,					/* tp_as_mapping */
       
   849 	0,					/* tp_hash */
       
   850 	0,					/* tp_call */
       
   851 	0,					/* tp_str */
       
   852 	PyObject_GenericGetAttr,		/* tp_getattro */
       
   853 	0,					/* tp_setattro */
       
   854 	0,					/* tp_as_buffer */
       
   855 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
       
   856 	fileio_doc,				/* tp_doc */
       
   857 	0,					/* tp_traverse */
       
   858 	0,					/* tp_clear */
       
   859 	0,					/* tp_richcompare */
       
   860 	offsetof(PyFileIOObject, weakreflist),	/* tp_weaklistoffset */
       
   861 	0,					/* tp_iter */
       
   862 	0,					/* tp_iternext */
       
   863 	fileio_methods,				/* tp_methods */
       
   864 	0,					/* tp_members */
       
   865 	fileio_getsetlist,			/* tp_getset */
       
   866 	0,					/* tp_base */
       
   867 	0,					/* tp_dict */
       
   868 	0,					/* tp_descr_get */
       
   869 	0,					/* tp_descr_set */
       
   870 	0,					/* tp_dictoffset */
       
   871 	fileio_init,				/* tp_init */
       
   872 	PyType_GenericAlloc,			/* tp_alloc */
       
   873 	fileio_new,				/* tp_new */
       
   874 	PyObject_Del,				/* tp_free */
       
   875 };
       
   876 
       
   877 static PyMethodDef module_methods[] = {
       
   878 	{NULL, NULL}
       
   879 };
       
   880 
       
   881 PyMODINIT_FUNC
       
   882 init_fileio(void)
       
   883 {
       
   884 	PyObject *m;	/* a module object */
       
   885 
       
   886 	m = Py_InitModule3("_fileio", module_methods,
       
   887 			   "Fast implementation of io.FileIO.");
       
   888 	if (m == NULL)
       
   889 		return;
       
   890 	if (PyType_Ready(&PyFileIO_Type) < 0)
       
   891 		return;
       
   892 	Py_INCREF(&PyFileIO_Type);
       
   893 	PyModule_AddObject(m, "_FileIO", (PyObject *) &PyFileIO_Type);
       
   894 }