+++ /dev/null
-/* Author: Daniel Stutzbach */\r
-\r
-#define PY_SSIZE_T_CLEAN\r
-#include "Python.h"\r
-#ifdef HAVE_SYS_TYPES_H\r
-#include <sys/types.h>\r
-#endif\r
-#ifdef HAVE_SYS_STAT_H\r
-#include <sys/stat.h>\r
-#endif\r
-#ifdef HAVE_FCNTL_H\r
-#include <fcntl.h>\r
-#endif\r
-#include <stddef.h> /* For offsetof */\r
-#include "_iomodule.h"\r
-\r
-/*\r
- * Known likely problems:\r
- *\r
- * - Files larger then 2**32-1\r
- * - Files with unicode filenames\r
- * - Passing numbers greater than 2**32-1 when an integer is expected\r
- * - Making it work on Windows and other oddball platforms\r
- *\r
- * To Do:\r
- *\r
- * - autoconfify header file inclusion\r
- */\r
-\r
-#ifdef MS_WINDOWS\r
-/* can simulate truncate with Win32 API functions; see file_truncate */\r
-#define HAVE_FTRUNCATE\r
-#define WIN32_LEAN_AND_MEAN\r
-#include <windows.h>\r
-#endif\r
-\r
-#if BUFSIZ < (8*1024)\r
-#define SMALLCHUNK (8*1024)\r
-#elif (BUFSIZ >= (2 << 25))\r
-#error "unreasonable BUFSIZ > 64MB defined"\r
-#else\r
-#define SMALLCHUNK BUFSIZ\r
-#endif\r
-\r
-typedef struct {\r
- PyObject_HEAD\r
- int fd;\r
- unsigned int readable : 1;\r
- unsigned int writable : 1;\r
- unsigned int appending : 1;\r
- signed int seekable : 2; /* -1 means unknown */\r
- unsigned int closefd : 1;\r
- PyObject *weakreflist;\r
- PyObject *dict;\r
-} fileio;\r
-\r
-PyTypeObject PyFileIO_Type;\r
-\r
-#define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))\r
-\r
-int\r
-_PyFileIO_closed(PyObject *self)\r
-{\r
- return ((fileio *)self)->fd < 0;\r
-}\r
-\r
-static PyObject *\r
-portable_lseek(int fd, PyObject *posobj, int whence);\r
-\r
-static PyObject *portable_lseek(int fd, PyObject *posobj, int whence);\r
-\r
-/* Returns 0 on success, -1 with exception set on failure. */\r
-static int\r
-internal_close(fileio *self)\r
-{\r
- int err = 0;\r
- int save_errno = 0;\r
- if (self->fd >= 0) {\r
- int fd = self->fd;\r
- self->fd = -1;\r
- /* fd is accessible and someone else may have closed it */\r
- if (_PyVerify_fd(fd)) {\r
- Py_BEGIN_ALLOW_THREADS\r
- err = close(fd);\r
- if (err < 0)\r
- save_errno = errno;\r
- Py_END_ALLOW_THREADS\r
- } else {\r
- save_errno = errno;\r
- err = -1;\r
- }\r
- }\r
- if (err < 0) {\r
- errno = save_errno;\r
- PyErr_SetFromErrno(PyExc_IOError);\r
- return -1;\r
- }\r
- return 0;\r
-}\r
-\r
-static PyObject *\r
-fileio_close(fileio *self)\r
-{\r
- PyObject *res;\r
- res = PyObject_CallMethod((PyObject*)&PyRawIOBase_Type,\r
- "close", "O", self);\r
- if (!self->closefd) {\r
- self->fd = -1;\r
- return res;\r
- }\r
- if (internal_close(self) < 0)\r
- Py_CLEAR(res);\r
- return res;\r
-}\r
-\r
-static PyObject *\r
-fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\r
-{\r
- fileio *self;\r
-\r
- assert(type != NULL && type->tp_alloc != NULL);\r
-\r
- self = (fileio *) type->tp_alloc(type, 0);\r
- if (self != NULL) {\r
- self->fd = -1;\r
- self->readable = 0;\r
- self->writable = 0;\r
- self->appending = 0;\r
- self->seekable = -1;\r
- self->closefd = 1;\r
- self->weakreflist = NULL;\r
- }\r
-\r
- return (PyObject *) self;\r
-}\r
-\r
-/* On Unix, open will succeed for directories.\r
- In Python, there should be no file objects referring to\r
- directories, so we need a check. */\r
-\r
-static int\r
-dircheck(fileio* self, PyObject *nameobj)\r
-{\r
-#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)\r
- struct stat buf;\r
- if (self->fd < 0)\r
- return 0;\r
- if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {\r
- errno = EISDIR;\r
- PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj);\r
- return -1;\r
- }\r
-#endif\r
- return 0;\r
-}\r
-\r
-static int\r
-check_fd(int fd)\r
-{\r
-#if defined(HAVE_FSTAT)\r
- struct stat buf;\r
- if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) {\r
- PyObject *exc;\r
- char *msg = strerror(EBADF);\r
- exc = PyObject_CallFunction(PyExc_OSError, "(is)",\r
- EBADF, msg);\r
- PyErr_SetObject(PyExc_OSError, exc);\r
- Py_XDECREF(exc);\r
- return -1;\r
- }\r
-#endif\r
- return 0;\r
-}\r
-\r
-\r
-static int\r
-fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)\r
-{\r
- fileio *self = (fileio *) oself;\r
- static char *kwlist[] = {"file", "mode", "closefd", NULL};\r
- const char *name = NULL;\r
- PyObject *nameobj, *stringobj = NULL;\r
- char *mode = "r";\r
- char *s;\r
-#ifdef MS_WINDOWS\r
- Py_UNICODE *widename = NULL;\r
-#endif\r
- int ret = 0;\r
- int rwa = 0, plus = 0;\r
- int flags = 0;\r
- int fd = -1;\r
- int closefd = 1;\r
- int fd_is_own = 0;\r
-\r
- assert(PyFileIO_Check(oself));\r
- if (self->fd >= 0) {\r
- if (self->closefd) {\r
- /* Have to close the existing file first. */\r
- if (internal_close(self) < 0)\r
- return -1;\r
- }\r
- else\r
- self->fd = -1;\r
- }\r
-\r
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:fileio",\r
- kwlist, &nameobj, &mode, &closefd))\r
- return -1;\r
-\r
- if (PyFloat_Check(nameobj)) {\r
- PyErr_SetString(PyExc_TypeError,\r
- "integer argument expected, got float");\r
- return -1;\r
- }\r
-\r
- fd = _PyLong_AsInt(nameobj);\r
- if (fd < 0) {\r
- if (!PyErr_Occurred()) {\r
- PyErr_SetString(PyExc_ValueError,\r
- "negative file descriptor");\r
- return -1;\r
- }\r
- PyErr_Clear();\r
- }\r
-\r
-#ifdef MS_WINDOWS\r
- if (PyUnicode_Check(nameobj))\r
- widename = PyUnicode_AS_UNICODE(nameobj);\r
- if (widename == NULL)\r
-#endif\r
- if (fd < 0)\r
- {\r
- if (PyBytes_Check(nameobj) || PyByteArray_Check(nameobj)) {\r
- Py_ssize_t namelen;\r
- if (PyObject_AsCharBuffer(nameobj, &name, &namelen) < 0)\r
- return -1;\r
- }\r
- else {\r
- PyObject *u = PyUnicode_FromObject(nameobj);\r
-\r
- if (u == NULL)\r
- return -1;\r
-\r
- stringobj = PyUnicode_AsEncodedString(\r
- u, Py_FileSystemDefaultEncoding, NULL);\r
- Py_DECREF(u);\r
- if (stringobj == NULL)\r
- return -1;\r
- if (!PyBytes_Check(stringobj)) {\r
- PyErr_SetString(PyExc_TypeError,\r
- "encoder failed to return bytes");\r
- goto error;\r
- }\r
- name = PyBytes_AS_STRING(stringobj);\r
- }\r
- }\r
-\r
- s = mode;\r
- while (*s) {\r
- switch (*s++) {\r
- case 'r':\r
- if (rwa) {\r
- bad_mode:\r
- PyErr_SetString(PyExc_ValueError,\r
- "Must have exactly one of read/write/append "\r
- "mode and at most one plus");\r
- goto error;\r
- }\r
- rwa = 1;\r
- self->readable = 1;\r
- break;\r
- case 'w':\r
- if (rwa)\r
- goto bad_mode;\r
- rwa = 1;\r
- self->writable = 1;\r
- flags |= O_CREAT | O_TRUNC;\r
- break;\r
- case 'a':\r
- if (rwa)\r
- goto bad_mode;\r
- rwa = 1;\r
- self->writable = 1;\r
- self->appending = 1;\r
- flags |= O_APPEND | O_CREAT;\r
- break;\r
- case 'b':\r
- break;\r
- case '+':\r
- if (plus)\r
- goto bad_mode;\r
- self->readable = self->writable = 1;\r
- plus = 1;\r
- break;\r
- default:\r
- PyErr_Format(PyExc_ValueError,\r
- "invalid mode: %.200s", mode);\r
- goto error;\r
- }\r
- }\r
-\r
- if (!rwa)\r
- goto bad_mode;\r
-\r
- if (self->readable && self->writable)\r
- flags |= O_RDWR;\r
- else if (self->readable)\r
- flags |= O_RDONLY;\r
- else\r
- flags |= O_WRONLY;\r
-\r
-#ifdef O_BINARY\r
- flags |= O_BINARY;\r
-#endif\r
-\r
- if (fd >= 0) {\r
- if (check_fd(fd))\r
- goto error;\r
- self->fd = fd;\r
- self->closefd = closefd;\r
- }\r
- else {\r
- self->closefd = 1;\r
- if (!closefd) {\r
- PyErr_SetString(PyExc_ValueError,\r
- "Cannot use closefd=False with file name");\r
- goto error;\r
- }\r
-\r
- Py_BEGIN_ALLOW_THREADS\r
- errno = 0;\r
-#ifdef MS_WINDOWS\r
- if (widename != NULL)\r
- self->fd = _wopen(widename, flags, 0666);\r
- else\r
-#endif\r
- self->fd = open(name, flags, 0666);\r
- Py_END_ALLOW_THREADS\r
- fd_is_own = 1;\r
- if (self->fd < 0) {\r
-#ifdef MS_WINDOWS\r
- if (widename != NULL)\r
- PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename);\r
- else\r
-#endif\r
- PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);\r
- goto error;\r
- }\r
- }\r
- if (dircheck(self, nameobj) < 0)\r
- goto error;\r
-\r
- if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0)\r
- goto error;\r
-\r
- if (self->appending) {\r
- /* For consistent behaviour, we explicitly seek to the\r
- end of file (otherwise, it might be done only on the\r
- first write()). */\r
- PyObject *pos = portable_lseek(self->fd, NULL, 2);\r
- if (pos == NULL)\r
- goto error;\r
- Py_DECREF(pos);\r
- }\r
-\r
- goto done;\r
-\r
- error:\r
- if (!fd_is_own)\r
- self->fd = -1;\r
-\r
- ret = -1;\r
-\r
- done:\r
- Py_CLEAR(stringobj);\r
- return ret;\r
-}\r
-\r
-static int\r
-fileio_traverse(fileio *self, visitproc visit, void *arg)\r
-{\r
- Py_VISIT(self->dict);\r
- return 0;\r
-}\r
-\r
-static int\r
-fileio_clear(fileio *self)\r
-{\r
- Py_CLEAR(self->dict);\r
- return 0;\r
-}\r
-\r
-static void\r
-fileio_dealloc(fileio *self)\r
-{\r
- if (_PyIOBase_finalize((PyObject *) self) < 0)\r
- return;\r
- _PyObject_GC_UNTRACK(self);\r
- if (self->weakreflist != NULL)\r
- PyObject_ClearWeakRefs((PyObject *) self);\r
- Py_CLEAR(self->dict);\r
- Py_TYPE(self)->tp_free((PyObject *)self);\r
-}\r
-\r
-static PyObject *\r
-err_closed(void)\r
-{\r
- PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");\r
- return NULL;\r
-}\r
-\r
-static PyObject *\r
-err_mode(char *action)\r
-{\r
- PyErr_Format(PyExc_ValueError, "File not open for %s", action);\r
- return NULL;\r
-}\r
-\r
-static PyObject *\r
-fileio_fileno(fileio *self)\r
-{\r
- if (self->fd < 0)\r
- return err_closed();\r
- return PyInt_FromLong((long) self->fd);\r
-}\r
-\r
-static PyObject *\r
-fileio_readable(fileio *self)\r
-{\r
- if (self->fd < 0)\r
- return err_closed();\r
- return PyBool_FromLong((long) self->readable);\r
-}\r
-\r
-static PyObject *\r
-fileio_writable(fileio *self)\r
-{\r
- if (self->fd < 0)\r
- return err_closed();\r
- return PyBool_FromLong((long) self->writable);\r
-}\r
-\r
-static PyObject *\r
-fileio_seekable(fileio *self)\r
-{\r
- if (self->fd < 0)\r
- return err_closed();\r
- if (self->seekable < 0) {\r
- PyObject *pos = portable_lseek(self->fd, NULL, SEEK_CUR);\r
- if (pos == NULL) {\r
- PyErr_Clear();\r
- self->seekable = 0;\r
- } else {\r
- Py_DECREF(pos);\r
- self->seekable = 1;\r
- }\r
- }\r
- return PyBool_FromLong((long) self->seekable);\r
-}\r
-\r
-static PyObject *\r
-fileio_readinto(fileio *self, PyObject *args)\r
-{\r
- Py_buffer pbuf;\r
- Py_ssize_t n, len;\r
-\r
- if (self->fd < 0)\r
- return err_closed();\r
- if (!self->readable)\r
- return err_mode("reading");\r
-\r
- if (!PyArg_ParseTuple(args, "w*", &pbuf))\r
- return NULL;\r
-\r
- if (_PyVerify_fd(self->fd)) {\r
- len = pbuf.len;\r
- Py_BEGIN_ALLOW_THREADS\r
- errno = 0;\r
-#if defined(MS_WIN64) || defined(MS_WINDOWS)\r
- if (len > INT_MAX)\r
- len = INT_MAX;\r
- n = read(self->fd, pbuf.buf, (int)len);\r
-#else\r
- n = read(self->fd, pbuf.buf, len);\r
-#endif\r
- Py_END_ALLOW_THREADS\r
- } else\r
- n = -1;\r
- PyBuffer_Release(&pbuf);\r
- if (n < 0) {\r
- if (errno == EAGAIN)\r
- Py_RETURN_NONE;\r
- PyErr_SetFromErrno(PyExc_IOError);\r
- return NULL;\r
- }\r
-\r
- return PyLong_FromSsize_t(n);\r
-}\r
-\r
-static size_t\r
-new_buffersize(fileio *self, size_t currentsize)\r
-{\r
-#ifdef HAVE_FSTAT\r
- off_t pos, end;\r
- struct stat st;\r
- if (fstat(self->fd, &st) == 0) {\r
- end = st.st_size;\r
- pos = lseek(self->fd, 0L, SEEK_CUR);\r
- /* Files claiming a size smaller than SMALLCHUNK may\r
- actually be streaming pseudo-files. In this case, we\r
- apply the more aggressive algorithm below.\r
- */\r
- if (end >= SMALLCHUNK && end >= pos && pos >= 0) {\r
- /* Add 1 so if the file were to grow we'd notice. */\r
- return currentsize + end - pos + 1;\r
- }\r
- }\r
-#endif\r
- /* Expand the buffer by an amount proportional to the current size,\r
- giving us amortized linear-time behavior. Use a less-than-double\r
- growth factor to avoid excessive allocation. */\r
- return currentsize + (currentsize >> 3) + 6;\r
-}\r
-\r
-static PyObject *\r
-fileio_readall(fileio *self)\r
-{\r
- PyObject *result;\r
- Py_ssize_t total = 0;\r
- Py_ssize_t n;\r
-\r
- if (self->fd < 0)\r
- return err_closed();\r
- if (!_PyVerify_fd(self->fd))\r
- return PyErr_SetFromErrno(PyExc_IOError);\r
-\r
- result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);\r
- if (result == NULL)\r
- return NULL;\r
-\r
- while (1) {\r
- size_t newsize = new_buffersize(self, total);\r
- if (newsize > PY_SSIZE_T_MAX || newsize <= 0) {\r
- PyErr_SetString(PyExc_OverflowError,\r
- "unbounded read returned more bytes "\r
- "than a Python string can hold ");\r
- Py_DECREF(result);\r
- return NULL;\r
- }\r
-\r
- if (PyBytes_GET_SIZE(result) < (Py_ssize_t)newsize) {\r
- if (_PyBytes_Resize(&result, newsize) < 0)\r
- return NULL; /* result has been freed */\r
- }\r
- Py_BEGIN_ALLOW_THREADS\r
- errno = 0;\r
- n = newsize - total;\r
-#if defined(MS_WIN64) || defined(MS_WINDOWS)\r
- if (n > INT_MAX)\r
- n = INT_MAX;\r
- n = read(self->fd,\r
- PyBytes_AS_STRING(result) + total,\r
- (int)n);\r
-#else\r
- n = read(self->fd,\r
- PyBytes_AS_STRING(result) + total,\r
- n);\r
-#endif\r
- Py_END_ALLOW_THREADS\r
- if (n == 0)\r
- break;\r
- if (n < 0) {\r
- if (errno == EINTR) {\r
- if (PyErr_CheckSignals()) {\r
- Py_DECREF(result);\r
- return NULL;\r
- }\r
- continue;\r
- }\r
- if (errno == EAGAIN) {\r
- if (total > 0)\r
- break;\r
- Py_DECREF(result);\r
- Py_RETURN_NONE;\r
- }\r
- Py_DECREF(result);\r
- PyErr_SetFromErrno(PyExc_IOError);\r
- return NULL;\r
- }\r
- total += n;\r
- }\r
-\r
- if (PyBytes_GET_SIZE(result) > total) {\r
- if (_PyBytes_Resize(&result, total) < 0) {\r
- /* This should never happen, but just in case */\r
- return NULL;\r
- }\r
- }\r
- return result;\r
-}\r
-\r
-static PyObject *\r
-fileio_read(fileio *self, PyObject *args)\r
-{\r
- char *ptr;\r
- Py_ssize_t n;\r
- Py_ssize_t size = -1;\r
- PyObject *bytes;\r
-\r
- if (self->fd < 0)\r
- return err_closed();\r
- if (!self->readable)\r
- return err_mode("reading");\r
-\r
- if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size))\r
- return NULL;\r
-\r
- if (size < 0) {\r
- return fileio_readall(self);\r
- }\r
-\r
-#if defined(MS_WIN64) || defined(MS_WINDOWS)\r
- if (size > INT_MAX)\r
- size = INT_MAX;\r
-#endif\r
- bytes = PyBytes_FromStringAndSize(NULL, size);\r
- if (bytes == NULL)\r
- return NULL;\r
- ptr = PyBytes_AS_STRING(bytes);\r
-\r
- if (_PyVerify_fd(self->fd)) {\r
- Py_BEGIN_ALLOW_THREADS\r
- errno = 0;\r
-#if defined(MS_WIN64) || defined(MS_WINDOWS)\r
- n = read(self->fd, ptr, (int)size);\r
-#else\r
- n = read(self->fd, ptr, size);\r
-#endif\r
- Py_END_ALLOW_THREADS\r
- } else\r
- n = -1;\r
-\r
- if (n < 0) {\r
- Py_DECREF(bytes);\r
- if (errno == EAGAIN)\r
- Py_RETURN_NONE;\r
- PyErr_SetFromErrno(PyExc_IOError);\r
- return NULL;\r
- }\r
-\r
- if (n != size) {\r
- if (_PyBytes_Resize(&bytes, n) < 0)\r
- return NULL;\r
- }\r
-\r
- return (PyObject *) bytes;\r
-}\r
-\r
-static PyObject *\r
-fileio_write(fileio *self, PyObject *args)\r
-{\r
- Py_buffer pbuf;\r
- Py_ssize_t n, len;\r
-\r
- if (self->fd < 0)\r
- return err_closed();\r
- if (!self->writable)\r
- return err_mode("writing");\r
-\r
- if (!PyArg_ParseTuple(args, "s*", &pbuf))\r
- return NULL;\r
-\r
- if (_PyVerify_fd(self->fd)) {\r
- Py_BEGIN_ALLOW_THREADS\r
- errno = 0;\r
- len = pbuf.len;\r
-#if defined(MS_WIN64) || defined(MS_WINDOWS)\r
- if (len > INT_MAX)\r
- len = INT_MAX;\r
- n = write(self->fd, pbuf.buf, (int)len);\r
-#else\r
- n = write(self->fd, pbuf.buf, len);\r
-#endif\r
- Py_END_ALLOW_THREADS\r
- } else\r
- n = -1;\r
-\r
- PyBuffer_Release(&pbuf);\r
-\r
- if (n < 0) {\r
- if (errno == EAGAIN)\r
- Py_RETURN_NONE;\r
- PyErr_SetFromErrno(PyExc_IOError);\r
- return NULL;\r
- }\r
-\r
- return PyLong_FromSsize_t(n);\r
-}\r
-\r
-/* XXX Windows support below is likely incomplete */\r
-\r
-/* Cribbed from posix_lseek() */\r
-static PyObject *\r
-portable_lseek(int fd, PyObject *posobj, int whence)\r
-{\r
- Py_off_t pos, res;\r
-\r
-#ifdef SEEK_SET\r
- /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */\r
- switch (whence) {\r
-#if SEEK_SET != 0\r
- case 0: whence = SEEK_SET; break;\r
-#endif\r
-#if SEEK_CUR != 1\r
- case 1: whence = SEEK_CUR; break;\r
-#endif\r
-#if SEEK_END != 2\r
- case 2: whence = SEEK_END; break;\r
-#endif\r
- }\r
-#endif /* SEEK_SET */\r
-\r
- if (posobj == NULL)\r
- pos = 0;\r
- else {\r
- if(PyFloat_Check(posobj)) {\r
- PyErr_SetString(PyExc_TypeError, "an integer is required");\r
- return NULL;\r
- }\r
-#if defined(HAVE_LARGEFILE_SUPPORT)\r
- pos = PyLong_AsLongLong(posobj);\r
-#else\r
- pos = PyLong_AsLong(posobj);\r
-#endif\r
- if (PyErr_Occurred())\r
- return NULL;\r
- }\r
-\r
- if (_PyVerify_fd(fd)) {\r
- Py_BEGIN_ALLOW_THREADS\r
-#if defined(MS_WIN64) || defined(MS_WINDOWS)\r
- res = _lseeki64(fd, pos, whence);\r
-#else\r
- res = lseek(fd, pos, whence);\r
-#endif\r
- Py_END_ALLOW_THREADS\r
- } else\r
- res = -1;\r
- if (res < 0)\r
- return PyErr_SetFromErrno(PyExc_IOError);\r
-\r
-#if defined(HAVE_LARGEFILE_SUPPORT)\r
- return PyLong_FromLongLong(res);\r
-#else\r
- return PyLong_FromLong(res);\r
-#endif\r
-}\r
-\r
-static PyObject *\r
-fileio_seek(fileio *self, PyObject *args)\r
-{\r
- PyObject *posobj;\r
- int whence = 0;\r
-\r
- if (self->fd < 0)\r
- return err_closed();\r
-\r
- if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))\r
- return NULL;\r
-\r
- return portable_lseek(self->fd, posobj, whence);\r
-}\r
-\r
-static PyObject *\r
-fileio_tell(fileio *self, PyObject *args)\r
-{\r
- if (self->fd < 0)\r
- return err_closed();\r
-\r
- return portable_lseek(self->fd, NULL, 1);\r
-}\r
-\r
-#ifdef HAVE_FTRUNCATE\r
-static PyObject *\r
-fileio_truncate(fileio *self, PyObject *args)\r
-{\r
- PyObject *posobj = NULL; /* the new size wanted by the user */\r
-#ifndef MS_WINDOWS\r
- Py_off_t pos;\r
-#endif\r
- int ret;\r
- int fd;\r
-\r
- fd = self->fd;\r
- if (fd < 0)\r
- return err_closed();\r
- if (!self->writable)\r
- return err_mode("writing");\r
-\r
- if (!PyArg_ParseTuple(args, "|O", &posobj))\r
- return NULL;\r
-\r
- if (posobj == Py_None || posobj == NULL) {\r
- /* Get the current position. */\r
- posobj = portable_lseek(fd, NULL, 1);\r
- if (posobj == NULL)\r
- return NULL;\r
- }\r
- else {\r
- Py_INCREF(posobj);\r
- }\r
-\r
-#ifdef MS_WINDOWS\r
- /* MS _chsize doesn't work if newsize doesn't fit in 32 bits,\r
- so don't even try using it. */\r
- {\r
- PyObject *oldposobj, *tempposobj;\r
- HANDLE hFile;\r
-\r
- /* we save the file pointer position */\r
- oldposobj = portable_lseek(fd, NULL, 1);\r
- if (oldposobj == NULL) {\r
- Py_DECREF(posobj);\r
- return NULL;\r
- }\r
-\r
- /* we then move to the truncation position */\r
- tempposobj = portable_lseek(fd, posobj, 0);\r
- if (tempposobj == NULL) {\r
- Py_DECREF(oldposobj);\r
- Py_DECREF(posobj);\r
- return NULL;\r
- }\r
- Py_DECREF(tempposobj);\r
-\r
- /* Truncate. Note that this may grow the file! */\r
- Py_BEGIN_ALLOW_THREADS\r
- errno = 0;\r
- hFile = (HANDLE)_get_osfhandle(fd);\r
- ret = hFile == (HANDLE)-1; /* testing for INVALID_HANDLE value */\r
- if (ret == 0) {\r
- ret = SetEndOfFile(hFile) == 0;\r
- if (ret)\r
- errno = EACCES;\r
- }\r
- Py_END_ALLOW_THREADS\r
-\r
- /* we restore the file pointer position in any case */\r
- tempposobj = portable_lseek(fd, oldposobj, 0);\r
- Py_DECREF(oldposobj);\r
- if (tempposobj == NULL) {\r
- Py_DECREF(posobj);\r
- return NULL;\r
- }\r
- Py_DECREF(tempposobj);\r
- }\r
-#else\r
-\r
-#if defined(HAVE_LARGEFILE_SUPPORT)\r
- pos = PyLong_AsLongLong(posobj);\r
-#else\r
- pos = PyLong_AsLong(posobj);\r
-#endif\r
- if (PyErr_Occurred()){\r
- Py_DECREF(posobj);\r
- return NULL;\r
- }\r
-\r
- Py_BEGIN_ALLOW_THREADS\r
- errno = 0;\r
- ret = ftruncate(fd, pos);\r
- Py_END_ALLOW_THREADS\r
-\r
-#endif /* !MS_WINDOWS */\r
-\r
- if (ret != 0) {\r
- Py_DECREF(posobj);\r
- PyErr_SetFromErrno(PyExc_IOError);\r
- return NULL;\r
- }\r
-\r
- return posobj;\r
-}\r
-#endif /* HAVE_FTRUNCATE */\r
-\r
-static char *\r
-mode_string(fileio *self)\r
-{\r
- if (self->appending) {\r
- if (self->readable)\r
- return "ab+";\r
- else\r
- return "ab";\r
- }\r
- else if (self->readable) {\r
- if (self->writable)\r
- return "rb+";\r
- else\r
- return "rb";\r
- }\r
- else\r
- return "wb";\r
-}\r
-\r
-static PyObject *\r
-fileio_repr(fileio *self)\r
-{\r
- PyObject *nameobj, *res;\r
-\r
- if (self->fd < 0)\r
- return PyString_FromFormat("<_io.FileIO [closed]>");\r
-\r
- nameobj = PyObject_GetAttrString((PyObject *) self, "name");\r
- if (nameobj == NULL) {\r
- if (PyErr_ExceptionMatches(PyExc_AttributeError))\r
- PyErr_Clear();\r
- else\r
- return NULL;\r
- res = PyString_FromFormat("<_io.FileIO fd=%d mode='%s'>",\r
- self->fd, mode_string(self));\r
- }\r
- else {\r
- PyObject *repr = PyObject_Repr(nameobj);\r
- Py_DECREF(nameobj);\r
- if (repr == NULL)\r
- return NULL;\r
- res = PyString_FromFormat("<_io.FileIO name=%s mode='%s'>",\r
- PyString_AS_STRING(repr),\r
- mode_string(self));\r
- Py_DECREF(repr);\r
- }\r
- return res;\r
-}\r
-\r
-static PyObject *\r
-fileio_isatty(fileio *self)\r
-{\r
- long res;\r
-\r
- if (self->fd < 0)\r
- return err_closed();\r
- Py_BEGIN_ALLOW_THREADS\r
- res = isatty(self->fd);\r
- Py_END_ALLOW_THREADS\r
- return PyBool_FromLong(res);\r
-}\r
-\r
-\r
-PyDoc_STRVAR(fileio_doc,\r
-"file(name: str[, mode: str]) -> file IO object\n"\r
-"\n"\r
-"Open a file. The mode can be 'r' (default), 'w' or 'a' for reading,\n"\r
-"writing or appending. The file will be created if it doesn't exist\n"\r
-"when opened for writing or appending; it will be truncated when\n"\r
-"opened for writing. Add a '+' to the mode to allow simultaneous\n"\r
-"reading and writing.");\r
-\r
-PyDoc_STRVAR(read_doc,\r
-"read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"\r
-"\n"\r
-"Only makes one system call, so less data may be returned than requested\n"\r
-"In non-blocking mode, returns None if no data is available.\n"\r
-"On end-of-file, returns ''.");\r
-\r
-PyDoc_STRVAR(readall_doc,\r
-"readall() -> bytes. read all data from the file, returned as bytes.\n"\r
-"\n"\r
-"In non-blocking mode, returns as much as is immediately available,\n"\r
-"or None if no data is available. On end-of-file, returns ''.");\r
-\r
-PyDoc_STRVAR(write_doc,\r
-"write(b: bytes) -> int. Write bytes b to file, return number written.\n"\r
-"\n"\r
-"Only makes one system call, so not all of the data may be written.\n"\r
-"The number of bytes actually written is returned. In non-blocking mode,\n"\r
-"returns None if the write would block."\r
-);\r
-\r
-PyDoc_STRVAR(fileno_doc,\r
-"fileno() -> int. Return the underlying file descriptor (an integer).");\r
-\r
-PyDoc_STRVAR(seek_doc,\r
-"seek(offset: int[, whence: int]) -> int. Move to new file position\n"\r
-"and return the file position.\n"\r
-"\n"\r
-"Argument offset is a byte count. Optional argument whence defaults to\n"\r
-"SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n"\r
-"are SEEK_CUR or 1 (move relative to current position, positive or negative),\n"\r
-"and SEEK_END or 2 (move relative to end of file, usually negative, although\n"\r
-"many platforms allow seeking beyond the end of a file).\n"\r
-"\n"\r
-"Note that not all file objects are seekable.");\r
-\r
-#ifdef HAVE_FTRUNCATE\r
-PyDoc_STRVAR(truncate_doc,\r
-"truncate([size: int]) -> int. Truncate the file to at most size bytes and\n"\r
-"return the truncated size.\n"\r
-"\n"\r
-"Size defaults to the current file position, as returned by tell().\n"\r
-"The current file position is changed to the value of size.");\r
-#endif\r
-\r
-PyDoc_STRVAR(tell_doc,\r
-"tell() -> int. Current file position.\n"\r
-"\n"\r
-"Can raise OSError for non seekable files."\r
-);\r
-\r
-PyDoc_STRVAR(readinto_doc,\r
-"readinto() -> Same as RawIOBase.readinto().");\r
-\r
-PyDoc_STRVAR(close_doc,\r
-"close() -> None. Close the file.\n"\r
-"\n"\r
-"A closed file cannot be used for further I/O operations. close() may be\n"\r
-"called more than once without error.");\r
-\r
-PyDoc_STRVAR(isatty_doc,\r
-"isatty() -> bool. True if the file is connected to a TTY device.");\r
-\r
-PyDoc_STRVAR(seekable_doc,\r
-"seekable() -> bool. True if file supports random-access.");\r
-\r
-PyDoc_STRVAR(readable_doc,\r
-"readable() -> bool. True if file was opened in a read mode.");\r
-\r
-PyDoc_STRVAR(writable_doc,\r
-"writable() -> bool. True if file was opened in a write mode.");\r
-\r
-static PyMethodDef fileio_methods[] = {\r
- {"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc},\r
- {"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc},\r
- {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},\r
- {"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc},\r
- {"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc},\r
- {"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc},\r
-#ifdef HAVE_FTRUNCATE\r
- {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},\r
-#endif\r
- {"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc},\r
- {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc},\r
- {"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc},\r
- {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc},\r
- {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc},\r
- {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc},\r
- {NULL, NULL} /* sentinel */\r
-};\r
-\r
-/* 'closed' and 'mode' are attributes for backwards compatibility reasons. */\r
-\r
-static PyObject *\r
-get_closed(fileio *self, void *closure)\r
-{\r
- return PyBool_FromLong((long)(self->fd < 0));\r
-}\r
-\r
-static PyObject *\r
-get_closefd(fileio *self, void *closure)\r
-{\r
- return PyBool_FromLong((long)(self->closefd));\r
-}\r
-\r
-static PyObject *\r
-get_mode(fileio *self, void *closure)\r
-{\r
- return PyUnicode_FromString(mode_string(self));\r
-}\r
-\r
-static PyGetSetDef fileio_getsetlist[] = {\r
- {"closed", (getter)get_closed, NULL, "True if the file is closed"},\r
- {"closefd", (getter)get_closefd, NULL,\r
- "True if the file descriptor will be closed by close()."},\r
- {"mode", (getter)get_mode, NULL, "String giving the file mode"},\r
- {NULL},\r
-};\r
-\r
-PyTypeObject PyFileIO_Type = {\r
- PyVarObject_HEAD_INIT(NULL, 0)\r
- "_io.FileIO",\r
- sizeof(fileio),\r
- 0,\r
- (destructor)fileio_dealloc, /* tp_dealloc */\r
- 0, /* tp_print */\r
- 0, /* tp_getattr */\r
- 0, /* tp_setattr */\r
- 0, /* tp_reserved */\r
- (reprfunc)fileio_repr, /* tp_repr */\r
- 0, /* tp_as_number */\r
- 0, /* tp_as_sequence */\r
- 0, /* tp_as_mapping */\r
- 0, /* tp_hash */\r
- 0, /* tp_call */\r
- 0, /* tp_str */\r
- PyObject_GenericGetAttr, /* tp_getattro */\r
- 0, /* tp_setattro */\r
- 0, /* tp_as_buffer */\r
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE\r
- | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r
- fileio_doc, /* tp_doc */\r
- (traverseproc)fileio_traverse, /* tp_traverse */\r
- (inquiry)fileio_clear, /* tp_clear */\r
- 0, /* tp_richcompare */\r
- offsetof(fileio, weakreflist), /* tp_weaklistoffset */\r
- 0, /* tp_iter */\r
- 0, /* tp_iternext */\r
- fileio_methods, /* tp_methods */\r
- 0, /* tp_members */\r
- fileio_getsetlist, /* tp_getset */\r
- 0, /* tp_base */\r
- 0, /* tp_dict */\r
- 0, /* tp_descr_get */\r
- 0, /* tp_descr_set */\r
- offsetof(fileio, dict), /* tp_dictoffset */\r
- fileio_init, /* tp_init */\r
- PyType_GenericAlloc, /* tp_alloc */\r
- fileio_new, /* tp_new */\r
- PyObject_GC_Del, /* tp_free */\r
-};\r