| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1 | /* Author: Daniel Stutzbach */ | 
|  | 2 |  | 
|  | 3 | #define PY_SSIZE_T_CLEAN | 
|  | 4 | #include "Python.h" | 
| Antoine Pitrou | e033e06 | 2010-10-29 10:38:18 +0000 | [diff] [blame] | 5 | #include "structmember.h" | 
| Benjamin Peterson | 2614cda | 2010-03-21 22:36:19 +0000 | [diff] [blame] | 6 | #ifdef HAVE_SYS_TYPES_H | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 7 | #include <sys/types.h> | 
| Benjamin Peterson | 2614cda | 2010-03-21 22:36:19 +0000 | [diff] [blame] | 8 | #endif | 
|  | 9 | #ifdef HAVE_SYS_STAT_H | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 10 | #include <sys/stat.h> | 
| Benjamin Peterson | 2614cda | 2010-03-21 22:36:19 +0000 | [diff] [blame] | 11 | #endif | 
|  | 12 | #ifdef HAVE_FCNTL_H | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 13 | #include <fcntl.h> | 
| Benjamin Peterson | 2614cda | 2010-03-21 22:36:19 +0000 | [diff] [blame] | 14 | #endif | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 15 | #include <stddef.h> /* For offsetof */ | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 16 | #include "_iomodule.h" | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 17 |  | 
|  | 18 | /* | 
|  | 19 | * Known likely problems: | 
|  | 20 | * | 
|  | 21 | * - Files larger then 2**32-1 | 
|  | 22 | * - Files with unicode filenames | 
|  | 23 | * - Passing numbers greater than 2**32-1 when an integer is expected | 
|  | 24 | * - Making it work on Windows and other oddball platforms | 
|  | 25 | * | 
|  | 26 | * To Do: | 
|  | 27 | * | 
|  | 28 | * - autoconfify header file inclusion | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 29 | */ | 
|  | 30 |  | 
|  | 31 | #ifdef MS_WINDOWS | 
|  | 32 | /* can simulate truncate with Win32 API functions; see file_truncate */ | 
| Thomas Heller | fdeee3a | 2007-07-12 11:21:36 +0000 | [diff] [blame] | 33 | #define HAVE_FTRUNCATE | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 34 | #define WIN32_LEAN_AND_MEAN | 
|  | 35 | #include <windows.h> | 
|  | 36 | #endif | 
|  | 37 |  | 
| Christian Heimes | a872de5 | 2008-12-05 08:26:55 +0000 | [diff] [blame] | 38 | #if BUFSIZ < (8*1024) | 
|  | 39 | #define SMALLCHUNK (8*1024) | 
|  | 40 | #elif (BUFSIZ >= (2 << 25)) | 
|  | 41 | #error "unreasonable BUFSIZ > 64MB defined" | 
|  | 42 | #else | 
|  | 43 | #define SMALLCHUNK BUFSIZ | 
|  | 44 | #endif | 
|  | 45 |  | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 46 | typedef struct { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 47 | PyObject_HEAD | 
|  | 48 | int fd; | 
| Charles-François Natali | dc3044c | 2012-01-09 22:40:02 +0100 | [diff] [blame] | 49 | unsigned int created : 1; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 50 | unsigned int readable : 1; | 
|  | 51 | unsigned int writable : 1; | 
|  | 52 | signed int seekable : 2; /* -1 means unknown */ | 
|  | 53 | unsigned int closefd : 1; | 
| Antoine Pitrou | e033e06 | 2010-10-29 10:38:18 +0000 | [diff] [blame] | 54 | unsigned int deallocating: 1; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 55 | PyObject *weakreflist; | 
|  | 56 | PyObject *dict; | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 57 | } fileio; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 58 |  | 
| Collin Winter | af33438 | 2007-03-08 21:46:15 +0000 | [diff] [blame] | 59 | PyTypeObject PyFileIO_Type; | 
|  | 60 |  | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 61 | #define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type)) | 
|  | 62 |  | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 63 | int | 
|  | 64 | _PyFileIO_closed(PyObject *self) | 
|  | 65 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 66 | return ((fileio *)self)->fd < 0; | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 67 | } | 
| Antoine Pitrou | 08838b6 | 2009-01-21 00:55:13 +0000 | [diff] [blame] | 68 |  | 
| Antoine Pitrou | e033e06 | 2010-10-29 10:38:18 +0000 | [diff] [blame] | 69 | /* Because this can call arbitrary code, it shouldn't be called when | 
|  | 70 | the refcount is 0 (that is, not directly from tp_dealloc unless | 
|  | 71 | the refcount has been temporarily re-incremented). */ | 
|  | 72 | static PyObject * | 
|  | 73 | fileio_dealloc_warn(fileio *self, PyObject *source) | 
|  | 74 | { | 
|  | 75 | if (self->fd >= 0 && self->closefd) { | 
|  | 76 | PyObject *exc, *val, *tb; | 
|  | 77 | PyErr_Fetch(&exc, &val, &tb); | 
|  | 78 | if (PyErr_WarnFormat(PyExc_ResourceWarning, 1, | 
|  | 79 | "unclosed file %R", source)) { | 
|  | 80 | /* Spurious errors can appear at shutdown */ | 
|  | 81 | if (PyErr_ExceptionMatches(PyExc_Warning)) | 
|  | 82 | PyErr_WriteUnraisable((PyObject *) self); | 
|  | 83 | } | 
|  | 84 | PyErr_Restore(exc, val, tb); | 
|  | 85 | } | 
|  | 86 | Py_RETURN_NONE; | 
|  | 87 | } | 
|  | 88 |  | 
| Antoine Pitrou | 7fb111b | 2009-03-04 11:14:01 +0000 | [diff] [blame] | 89 | static PyObject * | 
|  | 90 | portable_lseek(int fd, PyObject *posobj, int whence); | 
|  | 91 |  | 
| Antoine Pitrou | a28fcfd | 2009-03-13 23:42:55 +0000 | [diff] [blame] | 92 | static PyObject *portable_lseek(int fd, PyObject *posobj, int whence); | 
|  | 93 |  | 
| Kristján Valur Jónsson | 19288c2 | 2008-12-18 17:15:54 +0000 | [diff] [blame] | 94 | /* Returns 0 on success, -1 with exception set on failure. */ | 
| Neal Norwitz | 88b44da | 2007-08-12 17:23:54 +0000 | [diff] [blame] | 95 | static int | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 96 | internal_close(fileio *self) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 97 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 98 | int err = 0; | 
|  | 99 | int save_errno = 0; | 
|  | 100 | if (self->fd >= 0) { | 
|  | 101 | int fd = self->fd; | 
|  | 102 | self->fd = -1; | 
|  | 103 | /* fd is accessible and someone else may have closed it */ | 
|  | 104 | if (_PyVerify_fd(fd)) { | 
|  | 105 | Py_BEGIN_ALLOW_THREADS | 
|  | 106 | err = close(fd); | 
|  | 107 | if (err < 0) | 
|  | 108 | save_errno = errno; | 
|  | 109 | Py_END_ALLOW_THREADS | 
|  | 110 | } else { | 
|  | 111 | save_errno = errno; | 
|  | 112 | err = -1; | 
|  | 113 | } | 
|  | 114 | } | 
|  | 115 | if (err < 0) { | 
|  | 116 | errno = save_errno; | 
|  | 117 | PyErr_SetFromErrno(PyExc_IOError); | 
|  | 118 | return -1; | 
|  | 119 | } | 
|  | 120 | return 0; | 
| Neal Norwitz | 88b44da | 2007-08-12 17:23:54 +0000 | [diff] [blame] | 121 | } | 
|  | 122 |  | 
|  | 123 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 124 | fileio_close(fileio *self) | 
| Neal Norwitz | 88b44da | 2007-08-12 17:23:54 +0000 | [diff] [blame] | 125 | { | 
| Martin v. Löwis | bd928fe | 2011-10-14 10:20:37 +0200 | [diff] [blame] | 126 | _Py_IDENTIFIER(close); | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 127 | if (!self->closefd) { | 
|  | 128 | self->fd = -1; | 
|  | 129 | Py_RETURN_NONE; | 
|  | 130 | } | 
| Antoine Pitrou | e033e06 | 2010-10-29 10:38:18 +0000 | [diff] [blame] | 131 | if (self->deallocating) { | 
|  | 132 | PyObject *r = fileio_dealloc_warn(self, (PyObject *) self); | 
|  | 133 | if (r) | 
|  | 134 | Py_DECREF(r); | 
|  | 135 | else | 
|  | 136 | PyErr_Clear(); | 
|  | 137 | } | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 138 | errno = internal_close(self); | 
|  | 139 | if (errno < 0) | 
|  | 140 | return NULL; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 141 |  | 
| Martin v. Löwis | afe55bb | 2011-10-09 10:38:36 +0200 | [diff] [blame] | 142 | return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, | 
|  | 143 | &PyId_close, "O", self); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 144 | } | 
|  | 145 |  | 
|  | 146 | static PyObject * | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 147 | fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 148 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 149 | fileio *self; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 150 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 151 | assert(type != NULL && type->tp_alloc != NULL); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 152 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 153 | self = (fileio *) type->tp_alloc(type, 0); | 
|  | 154 | if (self != NULL) { | 
|  | 155 | self->fd = -1; | 
| Charles-François Natali | dc3044c | 2012-01-09 22:40:02 +0100 | [diff] [blame] | 156 | self->created = 0; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 157 | self->readable = 0; | 
|  | 158 | self->writable = 0; | 
|  | 159 | self->seekable = -1; | 
|  | 160 | self->closefd = 1; | 
|  | 161 | self->weakreflist = NULL; | 
|  | 162 | } | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 163 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 164 | return (PyObject *) self; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 165 | } | 
|  | 166 |  | 
|  | 167 | /* On Unix, open will succeed for directories. | 
|  | 168 | In Python, there should be no file objects referring to | 
|  | 169 | directories, so we need a check.  */ | 
|  | 170 |  | 
|  | 171 | static int | 
| Antoine Pitrou | 9235b25 | 2012-07-06 18:48:24 +0200 | [diff] [blame] | 172 | dircheck(fileio* self, PyObject *nameobj) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 173 | { | 
|  | 174 | #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 175 | struct stat buf; | 
|  | 176 | if (self->fd < 0) | 
|  | 177 | return 0; | 
|  | 178 | if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) { | 
| Antoine Pitrou | 9235b25 | 2012-07-06 18:48:24 +0200 | [diff] [blame] | 179 | errno = EISDIR; | 
|  | 180 | PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 181 | return -1; | 
|  | 182 | } | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 183 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 184 | return 0; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 185 | } | 
|  | 186 |  | 
| Benjamin Peterson | 806d402 | 2009-01-19 15:11:51 +0000 | [diff] [blame] | 187 | static int | 
|  | 188 | check_fd(int fd) | 
|  | 189 | { | 
|  | 190 | #if defined(HAVE_FSTAT) | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 191 | struct stat buf; | 
|  | 192 | if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) { | 
|  | 193 | PyObject *exc; | 
|  | 194 | char *msg = strerror(EBADF); | 
|  | 195 | exc = PyObject_CallFunction(PyExc_OSError, "(is)", | 
|  | 196 | EBADF, msg); | 
|  | 197 | PyErr_SetObject(PyExc_OSError, exc); | 
|  | 198 | Py_XDECREF(exc); | 
|  | 199 | return -1; | 
|  | 200 | } | 
| Benjamin Peterson | 806d402 | 2009-01-19 15:11:51 +0000 | [diff] [blame] | 201 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 202 | return 0; | 
| Benjamin Peterson | 806d402 | 2009-01-19 15:11:51 +0000 | [diff] [blame] | 203 | } | 
|  | 204 |  | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 205 |  | 
|  | 206 | static int | 
|  | 207 | fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) | 
|  | 208 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 209 | fileio *self = (fileio *) oself; | 
| Ross Lagerwall | 59142db | 2011-10-31 20:34:46 +0200 | [diff] [blame] | 210 | static char *kwlist[] = {"file", "mode", "closefd", "opener", NULL}; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 211 | const char *name = NULL; | 
| Ross Lagerwall | 59142db | 2011-10-31 20:34:46 +0200 | [diff] [blame] | 212 | PyObject *nameobj, *stringobj = NULL, *opener = Py_None; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 213 | char *mode = "r"; | 
|  | 214 | char *s; | 
| Thomas Heller | af2be26 | 2007-07-12 11:03:13 +0000 | [diff] [blame] | 215 | #ifdef MS_WINDOWS | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 216 | Py_UNICODE *widename = NULL; | 
| Thomas Heller | af2be26 | 2007-07-12 11:03:13 +0000 | [diff] [blame] | 217 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 218 | int ret = 0; | 
|  | 219 | int rwa = 0, plus = 0, append = 0; | 
|  | 220 | int flags = 0; | 
|  | 221 | int fd = -1; | 
|  | 222 | int closefd = 1; | 
| Hynek Schlawack | 9ed8b4e | 2012-06-21 20:20:25 +0200 | [diff] [blame] | 223 | int fd_is_own = 0; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 224 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 225 | assert(PyFileIO_Check(oself)); | 
|  | 226 | if (self->fd >= 0) { | 
| Hynek Schlawack | 2cc7156 | 2012-05-25 10:05:53 +0200 | [diff] [blame] | 227 | if (self->closefd) { | 
|  | 228 | /* Have to close the existing file first. */ | 
|  | 229 | if (internal_close(self) < 0) | 
|  | 230 | return -1; | 
|  | 231 | } | 
|  | 232 | else | 
|  | 233 | self->fd = -1; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 234 | } | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 235 |  | 
| Ross Lagerwall | 59142db | 2011-10-31 20:34:46 +0200 | [diff] [blame] | 236 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|siO:fileio", | 
|  | 237 | kwlist, &nameobj, &mode, &closefd, | 
|  | 238 | &opener)) | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 239 | return -1; | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 240 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 241 | if (PyFloat_Check(nameobj)) { | 
|  | 242 | PyErr_SetString(PyExc_TypeError, | 
|  | 243 | "integer argument expected, got float"); | 
|  | 244 | return -1; | 
|  | 245 | } | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 246 |  | 
| Serhiy Storchaka | 441d30f | 2013-01-19 12:26:26 +0200 | [diff] [blame] | 247 | fd = _PyLong_AsInt(nameobj); | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 248 | if (fd < 0) { | 
|  | 249 | if (!PyErr_Occurred()) { | 
|  | 250 | PyErr_SetString(PyExc_ValueError, | 
|  | 251 | "Negative filedescriptor"); | 
|  | 252 | return -1; | 
|  | 253 | } | 
|  | 254 | PyErr_Clear(); | 
|  | 255 | } | 
| Guido van Rossum | b042815 | 2007-04-08 17:44:42 +0000 | [diff] [blame] | 256 |  | 
| Hirokazu Yamamoto | 8223c24 | 2009-05-17 04:21:53 +0000 | [diff] [blame] | 257 | #ifdef MS_WINDOWS | 
| Victor Stinner | fe9a861 | 2011-09-29 23:19:04 +0200 | [diff] [blame] | 258 | if (PyUnicode_Check(nameobj)) { | 
| Antoine Pitrou | 1334884 | 2012-01-29 18:36:34 +0100 | [diff] [blame] | 259 | int rv = _PyUnicode_HasNULChars(nameobj); | 
|  | 260 | if (rv) { | 
|  | 261 | if (rv != -1) | 
|  | 262 | PyErr_SetString(PyExc_TypeError, "embedded NUL character"); | 
|  | 263 | return -1; | 
|  | 264 | } | 
| Victor Stinner | fe9a861 | 2011-09-29 23:19:04 +0200 | [diff] [blame] | 265 | widename = PyUnicode_AsUnicode(nameobj); | 
|  | 266 | if (widename == NULL) | 
|  | 267 | return -1; | 
|  | 268 | } else | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 269 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 270 | if (fd < 0) | 
|  | 271 | { | 
| Antoine Pitrou | 1334884 | 2012-01-29 18:36:34 +0100 | [diff] [blame] | 272 | if (!PyUnicode_FSConverter(nameobj, &stringobj)) { | 
|  | 273 | return -1; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 274 | } | 
| Antoine Pitrou | 1334884 | 2012-01-29 18:36:34 +0100 | [diff] [blame] | 275 | name = PyBytes_AS_STRING(stringobj); | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 276 | } | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 277 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 278 | s = mode; | 
|  | 279 | while (*s) { | 
|  | 280 | switch (*s++) { | 
| Charles-François Natali | dc3044c | 2012-01-09 22:40:02 +0100 | [diff] [blame] | 281 | case 'x': | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 282 | if (rwa) { | 
|  | 283 | bad_mode: | 
|  | 284 | PyErr_SetString(PyExc_ValueError, | 
| Charles-François Natali | dc3044c | 2012-01-09 22:40:02 +0100 | [diff] [blame] | 285 | "Must have exactly one of create/read/write/append " | 
| Georg Brandl | 28928ae | 2010-10-21 13:45:52 +0000 | [diff] [blame] | 286 | "mode and at most one plus"); | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 287 | goto error; | 
|  | 288 | } | 
|  | 289 | rwa = 1; | 
| Charles-François Natali | dc3044c | 2012-01-09 22:40:02 +0100 | [diff] [blame] | 290 | self->created = 1; | 
|  | 291 | self->writable = 1; | 
|  | 292 | flags |= O_EXCL | O_CREAT; | 
|  | 293 | break; | 
|  | 294 | case 'r': | 
|  | 295 | if (rwa) | 
|  | 296 | goto bad_mode; | 
|  | 297 | rwa = 1; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 298 | self->readable = 1; | 
|  | 299 | break; | 
|  | 300 | case 'w': | 
|  | 301 | if (rwa) | 
|  | 302 | goto bad_mode; | 
|  | 303 | rwa = 1; | 
|  | 304 | self->writable = 1; | 
|  | 305 | flags |= O_CREAT | O_TRUNC; | 
|  | 306 | break; | 
|  | 307 | case 'a': | 
|  | 308 | if (rwa) | 
|  | 309 | goto bad_mode; | 
|  | 310 | rwa = 1; | 
|  | 311 | self->writable = 1; | 
|  | 312 | flags |= O_CREAT; | 
|  | 313 | append = 1; | 
|  | 314 | break; | 
|  | 315 | case 'b': | 
|  | 316 | break; | 
|  | 317 | case '+': | 
|  | 318 | if (plus) | 
|  | 319 | goto bad_mode; | 
|  | 320 | self->readable = self->writable = 1; | 
|  | 321 | plus = 1; | 
|  | 322 | break; | 
|  | 323 | default: | 
|  | 324 | PyErr_Format(PyExc_ValueError, | 
|  | 325 | "invalid mode: %.200s", mode); | 
|  | 326 | goto error; | 
|  | 327 | } | 
|  | 328 | } | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 329 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 330 | if (!rwa) | 
|  | 331 | goto bad_mode; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 332 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 333 | if (self->readable && self->writable) | 
|  | 334 | flags |= O_RDWR; | 
|  | 335 | else if (self->readable) | 
|  | 336 | flags |= O_RDONLY; | 
|  | 337 | else | 
|  | 338 | flags |= O_WRONLY; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 339 |  | 
|  | 340 | #ifdef O_BINARY | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 341 | flags |= O_BINARY; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 342 | #endif | 
|  | 343 |  | 
| Walter Dörwald | 0e41148 | 2007-06-06 16:55:38 +0000 | [diff] [blame] | 344 | #ifdef O_APPEND | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 345 | if (append) | 
|  | 346 | flags |= O_APPEND; | 
| Walter Dörwald | 0e41148 | 2007-06-06 16:55:38 +0000 | [diff] [blame] | 347 | #endif | 
|  | 348 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 349 | if (fd >= 0) { | 
|  | 350 | if (check_fd(fd)) | 
|  | 351 | goto error; | 
|  | 352 | self->fd = fd; | 
|  | 353 | self->closefd = closefd; | 
|  | 354 | } | 
|  | 355 | else { | 
|  | 356 | self->closefd = 1; | 
|  | 357 | if (!closefd) { | 
|  | 358 | PyErr_SetString(PyExc_ValueError, | 
|  | 359 | "Cannot use closefd=False with file name"); | 
|  | 360 | goto error; | 
|  | 361 | } | 
| Guido van Rossum | 2dced8b | 2007-10-30 17:27:30 +0000 | [diff] [blame] | 362 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 363 | errno = 0; | 
| Ross Lagerwall | 59142db | 2011-10-31 20:34:46 +0200 | [diff] [blame] | 364 | if (opener == Py_None) { | 
|  | 365 | Py_BEGIN_ALLOW_THREADS | 
| Thomas Heller | af2be26 | 2007-07-12 11:03:13 +0000 | [diff] [blame] | 366 | #ifdef MS_WINDOWS | 
| Ross Lagerwall | 59142db | 2011-10-31 20:34:46 +0200 | [diff] [blame] | 367 | if (widename != NULL) | 
|  | 368 | self->fd = _wopen(widename, flags, 0666); | 
|  | 369 | else | 
| Thomas Heller | af2be26 | 2007-07-12 11:03:13 +0000 | [diff] [blame] | 370 | #endif | 
| Ross Lagerwall | 59142db | 2011-10-31 20:34:46 +0200 | [diff] [blame] | 371 | self->fd = open(name, flags, 0666); | 
|  | 372 | Py_END_ALLOW_THREADS | 
|  | 373 | } else { | 
|  | 374 | PyObject *fdobj = PyObject_CallFunction( | 
|  | 375 | opener, "Oi", nameobj, flags); | 
|  | 376 | if (fdobj == NULL) | 
|  | 377 | goto error; | 
|  | 378 | if (!PyLong_Check(fdobj)) { | 
|  | 379 | Py_DECREF(fdobj); | 
|  | 380 | PyErr_SetString(PyExc_TypeError, | 
|  | 381 | "expected integer from opener"); | 
|  | 382 | goto error; | 
|  | 383 | } | 
|  | 384 |  | 
| Serhiy Storchaka | 9101e23 | 2013-01-19 12:41:45 +0200 | [diff] [blame] | 385 | self->fd = _PyLong_AsInt(fdobj); | 
| Ross Lagerwall | 59142db | 2011-10-31 20:34:46 +0200 | [diff] [blame] | 386 | Py_DECREF(fdobj); | 
|  | 387 | if (self->fd == -1) { | 
|  | 388 | goto error; | 
|  | 389 | } | 
|  | 390 | } | 
|  | 391 |  | 
| Hynek Schlawack | 7f59fd7 | 2012-06-22 09:32:22 +0200 | [diff] [blame] | 392 | fd_is_own = 1; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 393 | if (self->fd < 0) { | 
| Christian Heimes | 0b48954 | 2007-10-31 19:20:48 +0000 | [diff] [blame] | 394 | #ifdef MS_WINDOWS | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 395 | if (widename != NULL) | 
| Victor Stinner | fe9a861 | 2011-09-29 23:19:04 +0200 | [diff] [blame] | 396 | PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 397 | else | 
| Christian Heimes | 0b48954 | 2007-10-31 19:20:48 +0000 | [diff] [blame] | 398 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 399 | PyErr_SetFromErrnoWithFilename(PyExc_IOError, name); | 
|  | 400 | goto error; | 
|  | 401 | } | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 402 | } | 
| Antoine Pitrou | 9235b25 | 2012-07-06 18:48:24 +0200 | [diff] [blame] | 403 | if (dircheck(self, nameobj) < 0) | 
|  | 404 | goto error; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 405 |  | 
| Victor Stinner | 89e3436 | 2011-01-07 18:47:22 +0000 | [diff] [blame] | 406 | #if defined(MS_WINDOWS) || defined(__CYGWIN__) | 
|  | 407 | /* don't translate newlines (\r\n <=> \n) */ | 
|  | 408 | _setmode(self->fd, O_BINARY); | 
|  | 409 | #endif | 
|  | 410 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 411 | if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0) | 
|  | 412 | goto error; | 
| Antoine Pitrou | 08838b6 | 2009-01-21 00:55:13 +0000 | [diff] [blame] | 413 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 414 | if (append) { | 
|  | 415 | /* For consistent behaviour, we explicitly seek to the | 
|  | 416 | end of file (otherwise, it might be done only on the | 
|  | 417 | first write()). */ | 
|  | 418 | PyObject *pos = portable_lseek(self->fd, NULL, 2); | 
| Hynek Schlawack | 9ed8b4e | 2012-06-21 20:20:25 +0200 | [diff] [blame] | 419 | if (pos == NULL) | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 420 | goto error; | 
|  | 421 | Py_DECREF(pos); | 
|  | 422 | } | 
| Antoine Pitrou | 7fb111b | 2009-03-04 11:14:01 +0000 | [diff] [blame] | 423 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 424 | goto done; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 425 |  | 
|  | 426 | error: | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 427 | ret = -1; | 
| Hynek Schlawack | 9ed8b4e | 2012-06-21 20:20:25 +0200 | [diff] [blame] | 428 | if (!fd_is_own) | 
|  | 429 | self->fd = -1; | 
| Benjamin Peterson | bbb0412 | 2010-10-30 23:16:28 +0000 | [diff] [blame] | 430 | if (self->fd >= 0) | 
|  | 431 | internal_close(self); | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 432 |  | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 433 | done: | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 434 | Py_CLEAR(stringobj); | 
|  | 435 | return ret; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 436 | } | 
|  | 437 |  | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 438 | static int | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 439 | fileio_traverse(fileio *self, visitproc visit, void *arg) | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 440 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 441 | Py_VISIT(self->dict); | 
|  | 442 | return 0; | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 443 | } | 
|  | 444 |  | 
|  | 445 | static int | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 446 | fileio_clear(fileio *self) | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 447 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 448 | Py_CLEAR(self->dict); | 
|  | 449 | return 0; | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 450 | } | 
|  | 451 |  | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 452 | static void | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 453 | fileio_dealloc(fileio *self) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 454 | { | 
| Antoine Pitrou | e033e06 | 2010-10-29 10:38:18 +0000 | [diff] [blame] | 455 | self->deallocating = 1; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 456 | if (_PyIOBase_finalize((PyObject *) self) < 0) | 
|  | 457 | return; | 
|  | 458 | _PyObject_GC_UNTRACK(self); | 
|  | 459 | if (self->weakreflist != NULL) | 
|  | 460 | PyObject_ClearWeakRefs((PyObject *) self); | 
|  | 461 | Py_CLEAR(self->dict); | 
|  | 462 | Py_TYPE(self)->tp_free((PyObject *)self); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 463 | } | 
|  | 464 |  | 
|  | 465 | static PyObject * | 
|  | 466 | err_closed(void) | 
|  | 467 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 468 | PyErr_SetString(PyExc_ValueError, "I/O operation on closed file"); | 
|  | 469 | return NULL; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 470 | } | 
|  | 471 |  | 
|  | 472 | static PyObject * | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 473 | err_mode(char *action) | 
|  | 474 | { | 
| Antoine Pitrou | 0d739d7 | 2010-09-05 23:01:12 +0000 | [diff] [blame] | 475 | PyErr_Format(IO_STATE->unsupported_operation, | 
|  | 476 | "File not open for %s", action); | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 477 | return NULL; | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 478 | } | 
|  | 479 |  | 
|  | 480 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 481 | fileio_fileno(fileio *self) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 482 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 483 | if (self->fd < 0) | 
|  | 484 | return err_closed(); | 
|  | 485 | return PyLong_FromLong((long) self->fd); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 486 | } | 
|  | 487 |  | 
|  | 488 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 489 | fileio_readable(fileio *self) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 490 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 491 | if (self->fd < 0) | 
|  | 492 | return err_closed(); | 
|  | 493 | return PyBool_FromLong((long) self->readable); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 494 | } | 
|  | 495 |  | 
|  | 496 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 497 | fileio_writable(fileio *self) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 498 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 499 | if (self->fd < 0) | 
|  | 500 | return err_closed(); | 
|  | 501 | return PyBool_FromLong((long) self->writable); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 502 | } | 
|  | 503 |  | 
|  | 504 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 505 | fileio_seekable(fileio *self) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 506 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 507 | if (self->fd < 0) | 
|  | 508 | return err_closed(); | 
|  | 509 | if (self->seekable < 0) { | 
|  | 510 | PyObject *pos = portable_lseek(self->fd, NULL, SEEK_CUR); | 
|  | 511 | if (pos == NULL) { | 
|  | 512 | PyErr_Clear(); | 
|  | 513 | self->seekable = 0; | 
|  | 514 | } else { | 
|  | 515 | Py_DECREF(pos); | 
|  | 516 | self->seekable = 1; | 
|  | 517 | } | 
|  | 518 | } | 
|  | 519 | return PyBool_FromLong((long) self->seekable); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 520 | } | 
|  | 521 |  | 
|  | 522 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 523 | fileio_readinto(fileio *self, PyObject *args) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 524 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 525 | Py_buffer pbuf; | 
| Victor Stinner | e6edec2 | 2011-01-04 00:29:35 +0000 | [diff] [blame] | 526 | Py_ssize_t n, len; | 
| Antoine Pitrou | c345ce1 | 2011-12-16 12:28:32 +0100 | [diff] [blame] | 527 | int err; | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 528 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 529 | if (self->fd < 0) | 
|  | 530 | return err_closed(); | 
|  | 531 | if (!self->readable) | 
|  | 532 | return err_mode("reading"); | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 533 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 534 | if (!PyArg_ParseTuple(args, "w*", &pbuf)) | 
|  | 535 | return NULL; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 536 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 537 | if (_PyVerify_fd(self->fd)) { | 
| Victor Stinner | e6edec2 | 2011-01-04 00:29:35 +0000 | [diff] [blame] | 538 | len = pbuf.len; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 539 | Py_BEGIN_ALLOW_THREADS | 
|  | 540 | errno = 0; | 
| Victor Stinner | e6edec2 | 2011-01-04 00:29:35 +0000 | [diff] [blame] | 541 | #if defined(MS_WIN64) || defined(MS_WINDOWS) | 
|  | 542 | if (len > INT_MAX) | 
|  | 543 | len = INT_MAX; | 
|  | 544 | n = read(self->fd, pbuf.buf, (int)len); | 
|  | 545 | #else | 
| Victor Stinner | 7234479 | 2011-01-11 00:04:12 +0000 | [diff] [blame] | 546 | n = read(self->fd, pbuf.buf, len); | 
| Victor Stinner | e6edec2 | 2011-01-04 00:29:35 +0000 | [diff] [blame] | 547 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 548 | Py_END_ALLOW_THREADS | 
|  | 549 | } else | 
|  | 550 | n = -1; | 
| Antoine Pitrou | c345ce1 | 2011-12-16 12:28:32 +0100 | [diff] [blame] | 551 | err = errno; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 552 | PyBuffer_Release(&pbuf); | 
|  | 553 | if (n < 0) { | 
| Antoine Pitrou | c345ce1 | 2011-12-16 12:28:32 +0100 | [diff] [blame] | 554 | if (err == EAGAIN) | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 555 | Py_RETURN_NONE; | 
| Antoine Pitrou | c345ce1 | 2011-12-16 12:28:32 +0100 | [diff] [blame] | 556 | errno = err; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 557 | PyErr_SetFromErrno(PyExc_IOError); | 
|  | 558 | return NULL; | 
|  | 559 | } | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 560 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 561 | return PyLong_FromSsize_t(n); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 562 | } | 
|  | 563 |  | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 564 | static size_t | 
| Victor Stinner | e9d44ccb | 2011-05-26 00:16:44 +0200 | [diff] [blame] | 565 | new_buffersize(fileio *self, size_t currentsize | 
|  | 566 | #ifdef HAVE_FSTAT | 
| Victor Stinner | a2a6477 | 2011-10-11 22:45:02 +0200 | [diff] [blame] | 567 | , Py_off_t pos, Py_off_t end | 
| Victor Stinner | e9d44ccb | 2011-05-26 00:16:44 +0200 | [diff] [blame] | 568 | #endif | 
|  | 569 | ) | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 570 | { | 
| Antoine Pitrou | a3f4457 | 2012-04-17 13:50:58 +0200 | [diff] [blame] | 571 | size_t addend; | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 572 | #ifdef HAVE_FSTAT | 
| Victor Stinner | a2a6477 | 2011-10-11 22:45:02 +0200 | [diff] [blame] | 573 | if (end != (Py_off_t)-1) { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 574 | /* Files claiming a size smaller than SMALLCHUNK may | 
|  | 575 | actually be streaming pseudo-files. In this case, we | 
|  | 576 | apply the more aggressive algorithm below. | 
|  | 577 | */ | 
|  | 578 | if (end >= SMALLCHUNK && end >= pos && pos >= 0) { | 
|  | 579 | /* Add 1 so if the file were to grow we'd notice. */ | 
| Victor Stinner | c5af773 | 2011-10-11 23:00:31 +0200 | [diff] [blame] | 580 | Py_off_t bufsize = currentsize + end - pos + 1; | 
|  | 581 | if (bufsize < PY_SSIZE_T_MAX) | 
|  | 582 | return (size_t)bufsize; | 
|  | 583 | else | 
|  | 584 | return PY_SSIZE_T_MAX; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 585 | } | 
|  | 586 | } | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 587 | #endif | 
| Nadeem Vawda | d41a98b | 2011-10-13 13:34:16 +0200 | [diff] [blame] | 588 | /* Expand the buffer by an amount proportional to the current size, | 
| Antoine Pitrou | a3f4457 | 2012-04-17 13:50:58 +0200 | [diff] [blame] | 589 | giving us amortized linear-time behavior.  For bigger sizes, use a | 
|  | 590 | less-than-double growth factor to avoid excessive allocation. */ | 
|  | 591 | if (currentsize > 65536) | 
|  | 592 | addend = currentsize >> 3; | 
|  | 593 | else | 
|  | 594 | addend = 256 + currentsize; | 
|  | 595 | if (addend < SMALLCHUNK) | 
|  | 596 | /* Avoid tiny read() calls. */ | 
|  | 597 | addend = SMALLCHUNK; | 
|  | 598 | return addend + currentsize; | 
| Benjamin Peterson | 4fa88fa | 2009-03-04 00:14:51 +0000 | [diff] [blame] | 599 | } | 
|  | 600 |  | 
| Guido van Rossum | 7165cb1 | 2007-07-10 06:54:34 +0000 | [diff] [blame] | 601 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 602 | fileio_readall(fileio *self) | 
| Guido van Rossum | 7165cb1 | 2007-07-10 06:54:34 +0000 | [diff] [blame] | 603 | { | 
| Victor Stinner | e9d44ccb | 2011-05-26 00:16:44 +0200 | [diff] [blame] | 604 | #ifdef HAVE_FSTAT | 
|  | 605 | struct stat st; | 
| Victor Stinner | a2a6477 | 2011-10-11 22:45:02 +0200 | [diff] [blame] | 606 | Py_off_t pos, end; | 
| Victor Stinner | e9d44ccb | 2011-05-26 00:16:44 +0200 | [diff] [blame] | 607 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 608 | PyObject *result; | 
|  | 609 | Py_ssize_t total = 0; | 
| Victor Stinner | c44057d | 2013-01-03 03:33:21 +0100 | [diff] [blame] | 610 | Py_ssize_t n; | 
| Victor Stinner | e9d44ccb | 2011-05-26 00:16:44 +0200 | [diff] [blame] | 611 | size_t newsize; | 
| Guido van Rossum | 7165cb1 | 2007-07-10 06:54:34 +0000 | [diff] [blame] | 612 |  | 
| Victor Stinner | b79f28c | 2011-05-25 22:09:03 +0200 | [diff] [blame] | 613 | if (self->fd < 0) | 
|  | 614 | return err_closed(); | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 615 | if (!_PyVerify_fd(self->fd)) | 
|  | 616 | return PyErr_SetFromErrno(PyExc_IOError); | 
| Kristján Valur Jónsson | a8abe86 | 2009-03-24 15:27:42 +0000 | [diff] [blame] | 617 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 618 | result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK); | 
|  | 619 | if (result == NULL) | 
|  | 620 | return NULL; | 
| Guido van Rossum | 7165cb1 | 2007-07-10 06:54:34 +0000 | [diff] [blame] | 621 |  | 
| Victor Stinner | e9d44ccb | 2011-05-26 00:16:44 +0200 | [diff] [blame] | 622 | #ifdef HAVE_FSTAT | 
|  | 623 | #if defined(MS_WIN64) || defined(MS_WINDOWS) | 
|  | 624 | pos = _lseeki64(self->fd, 0L, SEEK_CUR); | 
|  | 625 | #else | 
|  | 626 | pos = lseek(self->fd, 0L, SEEK_CUR); | 
|  | 627 | #endif | 
|  | 628 | if (fstat(self->fd, &st) == 0) | 
|  | 629 | end = st.st_size; | 
|  | 630 | else | 
| Victor Stinner | a2a6477 | 2011-10-11 22:45:02 +0200 | [diff] [blame] | 631 | end = (Py_off_t)-1; | 
| Victor Stinner | e9d44ccb | 2011-05-26 00:16:44 +0200 | [diff] [blame] | 632 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 633 | while (1) { | 
| Victor Stinner | e9d44ccb | 2011-05-26 00:16:44 +0200 | [diff] [blame] | 634 | #ifdef HAVE_FSTAT | 
|  | 635 | newsize = new_buffersize(self, total, pos, end); | 
|  | 636 | #else | 
|  | 637 | newsize = new_buffersize(self, total); | 
|  | 638 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 639 | if (newsize > PY_SSIZE_T_MAX || newsize <= 0) { | 
|  | 640 | PyErr_SetString(PyExc_OverflowError, | 
|  | 641 | "unbounded read returned more bytes " | 
|  | 642 | "than a Python string can hold "); | 
|  | 643 | Py_DECREF(result); | 
|  | 644 | return NULL; | 
|  | 645 | } | 
| Christian Heimes | a872de5 | 2008-12-05 08:26:55 +0000 | [diff] [blame] | 646 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 647 | if (PyBytes_GET_SIZE(result) < (Py_ssize_t)newsize) { | 
|  | 648 | if (_PyBytes_Resize(&result, newsize) < 0) { | 
|  | 649 | if (total == 0) { | 
|  | 650 | Py_DECREF(result); | 
|  | 651 | return NULL; | 
|  | 652 | } | 
|  | 653 | PyErr_Clear(); | 
|  | 654 | break; | 
|  | 655 | } | 
|  | 656 | } | 
|  | 657 | Py_BEGIN_ALLOW_THREADS | 
|  | 658 | errno = 0; | 
| Victor Stinner | c44057d | 2013-01-03 03:33:21 +0100 | [diff] [blame] | 659 | n = newsize - total; | 
|  | 660 | #if defined(MS_WIN64) || defined(MS_WINDOWS) | 
|  | 661 | if (n > INT_MAX) | 
|  | 662 | n = INT_MAX; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 663 | n = read(self->fd, | 
|  | 664 | PyBytes_AS_STRING(result) + total, | 
| Victor Stinner | c44057d | 2013-01-03 03:33:21 +0100 | [diff] [blame] | 665 | (int)n); | 
|  | 666 | #else | 
|  | 667 | n = read(self->fd, | 
|  | 668 | PyBytes_AS_STRING(result) + total, | 
|  | 669 | n); | 
|  | 670 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 671 | Py_END_ALLOW_THREADS | 
|  | 672 | if (n == 0) | 
|  | 673 | break; | 
|  | 674 | if (n < 0) { | 
| Gregory P. Smith | 5135992 | 2012-06-23 23:55:39 -0700 | [diff] [blame] | 675 | if (errno == EINTR) { | 
|  | 676 | if (PyErr_CheckSignals()) { | 
|  | 677 | Py_DECREF(result); | 
|  | 678 | return NULL; | 
|  | 679 | } | 
|  | 680 | continue; | 
|  | 681 | } | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 682 | if (total > 0) | 
|  | 683 | break; | 
|  | 684 | if (errno == EAGAIN) { | 
|  | 685 | Py_DECREF(result); | 
|  | 686 | Py_RETURN_NONE; | 
|  | 687 | } | 
|  | 688 | Py_DECREF(result); | 
|  | 689 | PyErr_SetFromErrno(PyExc_IOError); | 
|  | 690 | return NULL; | 
|  | 691 | } | 
|  | 692 | total += n; | 
| Victor Stinner | e9d44ccb | 2011-05-26 00:16:44 +0200 | [diff] [blame] | 693 | #ifdef HAVE_FSTAT | 
|  | 694 | pos += n; | 
|  | 695 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 696 | } | 
| Guido van Rossum | 7165cb1 | 2007-07-10 06:54:34 +0000 | [diff] [blame] | 697 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 698 | if (PyBytes_GET_SIZE(result) > total) { | 
|  | 699 | if (_PyBytes_Resize(&result, total) < 0) { | 
|  | 700 | /* This should never happen, but just in case */ | 
|  | 701 | Py_DECREF(result); | 
|  | 702 | return NULL; | 
|  | 703 | } | 
|  | 704 | } | 
|  | 705 | return result; | 
| Guido van Rossum | 7165cb1 | 2007-07-10 06:54:34 +0000 | [diff] [blame] | 706 | } | 
|  | 707 |  | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 708 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 709 | fileio_read(fileio *self, PyObject *args) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 710 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 711 | char *ptr; | 
|  | 712 | Py_ssize_t n; | 
|  | 713 | Py_ssize_t size = -1; | 
|  | 714 | PyObject *bytes; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 715 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 716 | if (self->fd < 0) | 
|  | 717 | return err_closed(); | 
|  | 718 | if (!self->readable) | 
|  | 719 | return err_mode("reading"); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 720 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 721 | if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size)) | 
|  | 722 | return NULL; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 723 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 724 | if (size < 0) { | 
|  | 725 | return fileio_readall(self); | 
|  | 726 | } | 
| Guido van Rossum | c2f93dc | 2007-05-24 00:50:02 +0000 | [diff] [blame] | 727 |  | 
| Victor Stinner | c655a72 | 2011-07-05 11:31:49 +0200 | [diff] [blame] | 728 | #if defined(MS_WIN64) || defined(MS_WINDOWS) | 
|  | 729 | if (size > INT_MAX) | 
|  | 730 | size = INT_MAX; | 
|  | 731 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 732 | bytes = PyBytes_FromStringAndSize(NULL, size); | 
|  | 733 | if (bytes == NULL) | 
|  | 734 | return NULL; | 
|  | 735 | ptr = PyBytes_AS_STRING(bytes); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 736 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 737 | if (_PyVerify_fd(self->fd)) { | 
|  | 738 | Py_BEGIN_ALLOW_THREADS | 
|  | 739 | errno = 0; | 
| Victor Stinner | c655a72 | 2011-07-05 11:31:49 +0200 | [diff] [blame] | 740 | #if defined(MS_WIN64) || defined(MS_WINDOWS) | 
|  | 741 | n = read(self->fd, ptr, (int)size); | 
|  | 742 | #else | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 743 | n = read(self->fd, ptr, size); | 
| Victor Stinner | c655a72 | 2011-07-05 11:31:49 +0200 | [diff] [blame] | 744 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 745 | Py_END_ALLOW_THREADS | 
|  | 746 | } else | 
|  | 747 | n = -1; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 748 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 749 | if (n < 0) { | 
| Antoine Pitrou | c345ce1 | 2011-12-16 12:28:32 +0100 | [diff] [blame] | 750 | int err = errno; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 751 | Py_DECREF(bytes); | 
| Antoine Pitrou | c345ce1 | 2011-12-16 12:28:32 +0100 | [diff] [blame] | 752 | if (err == EAGAIN) | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 753 | Py_RETURN_NONE; | 
| Antoine Pitrou | c345ce1 | 2011-12-16 12:28:32 +0100 | [diff] [blame] | 754 | errno = err; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 755 | PyErr_SetFromErrno(PyExc_IOError); | 
|  | 756 | return NULL; | 
|  | 757 | } | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 758 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 759 | if (n != size) { | 
|  | 760 | if (_PyBytes_Resize(&bytes, n) < 0) { | 
|  | 761 | Py_DECREF(bytes); | 
|  | 762 | return NULL; | 
|  | 763 | } | 
|  | 764 | } | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 765 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 766 | return (PyObject *) bytes; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 767 | } | 
|  | 768 |  | 
|  | 769 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 770 | fileio_write(fileio *self, PyObject *args) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 771 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 772 | Py_buffer pbuf; | 
| Victor Stinner | e6edec2 | 2011-01-04 00:29:35 +0000 | [diff] [blame] | 773 | Py_ssize_t n, len; | 
| Antoine Pitrou | c345ce1 | 2011-12-16 12:28:32 +0100 | [diff] [blame] | 774 | int err; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 775 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 776 | if (self->fd < 0) | 
|  | 777 | return err_closed(); | 
|  | 778 | if (!self->writable) | 
|  | 779 | return err_mode("writing"); | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 780 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 781 | if (!PyArg_ParseTuple(args, "y*", &pbuf)) | 
|  | 782 | return NULL; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 783 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 784 | if (_PyVerify_fd(self->fd)) { | 
|  | 785 | Py_BEGIN_ALLOW_THREADS | 
|  | 786 | errno = 0; | 
| Victor Stinner | e6edec2 | 2011-01-04 00:29:35 +0000 | [diff] [blame] | 787 | len = pbuf.len; | 
|  | 788 | #if defined(MS_WIN64) || defined(MS_WINDOWS) | 
| Victor Stinner | e0daff1 | 2011-03-20 23:36:35 +0100 | [diff] [blame] | 789 | if (len > 32767 && isatty(self->fd)) { | 
|  | 790 | /* Issue #11395: the Windows console returns an error (12: not | 
|  | 791 | enough space error) on writing into stdout if stdout mode is | 
|  | 792 | binary and the length is greater than 66,000 bytes (or less, | 
|  | 793 | depending on heap usage). */ | 
|  | 794 | len = 32767; | 
|  | 795 | } | 
|  | 796 | else if (len > INT_MAX) | 
| Victor Stinner | e6edec2 | 2011-01-04 00:29:35 +0000 | [diff] [blame] | 797 | len = INT_MAX; | 
|  | 798 | n = write(self->fd, pbuf.buf, (int)len); | 
|  | 799 | #else | 
| Victor Stinner | 7234479 | 2011-01-11 00:04:12 +0000 | [diff] [blame] | 800 | n = write(self->fd, pbuf.buf, len); | 
| Victor Stinner | e6edec2 | 2011-01-04 00:29:35 +0000 | [diff] [blame] | 801 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 802 | Py_END_ALLOW_THREADS | 
|  | 803 | } else | 
|  | 804 | n = -1; | 
| Antoine Pitrou | c345ce1 | 2011-12-16 12:28:32 +0100 | [diff] [blame] | 805 | err = errno; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 806 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 807 | PyBuffer_Release(&pbuf); | 
| Martin v. Löwis | 423be95 | 2008-08-13 15:53:07 +0000 | [diff] [blame] | 808 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 809 | if (n < 0) { | 
| Antoine Pitrou | c345ce1 | 2011-12-16 12:28:32 +0100 | [diff] [blame] | 810 | if (err == EAGAIN) | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 811 | Py_RETURN_NONE; | 
| Antoine Pitrou | c345ce1 | 2011-12-16 12:28:32 +0100 | [diff] [blame] | 812 | errno = err; | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 813 | PyErr_SetFromErrno(PyExc_IOError); | 
|  | 814 | return NULL; | 
|  | 815 | } | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 816 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 817 | return PyLong_FromSsize_t(n); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 818 | } | 
|  | 819 |  | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 820 | /* XXX Windows support below is likely incomplete */ | 
|  | 821 |  | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 822 | /* Cribbed from posix_lseek() */ | 
|  | 823 | static PyObject * | 
|  | 824 | portable_lseek(int fd, PyObject *posobj, int whence) | 
|  | 825 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 826 | Py_off_t pos, res; | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 827 |  | 
|  | 828 | #ifdef SEEK_SET | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 829 | /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */ | 
|  | 830 | switch (whence) { | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 831 | #if SEEK_SET != 0 | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 832 | case 0: whence = SEEK_SET; break; | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 833 | #endif | 
|  | 834 | #if SEEK_CUR != 1 | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 835 | case 1: whence = SEEK_CUR; break; | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 836 | #endif | 
| Antoine Pitrou | 4f7945f | 2009-01-20 11:42:11 +0000 | [diff] [blame] | 837 | #if SEEK_END != 2 | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 838 | case 2: whence = SEEK_END; break; | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 839 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 840 | } | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 841 | #endif /* SEEK_SET */ | 
|  | 842 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 843 | if (posobj == NULL) | 
|  | 844 | pos = 0; | 
|  | 845 | else { | 
|  | 846 | if(PyFloat_Check(posobj)) { | 
|  | 847 | PyErr_SetString(PyExc_TypeError, "an integer is required"); | 
|  | 848 | return NULL; | 
|  | 849 | } | 
| Alexandre Vassalotti | 77250f4 | 2008-05-06 19:48:38 +0000 | [diff] [blame] | 850 | #if defined(HAVE_LARGEFILE_SUPPORT) | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 851 | pos = PyLong_AsLongLong(posobj); | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 852 | #else | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 853 | pos = PyLong_AsLong(posobj); | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 854 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 855 | if (PyErr_Occurred()) | 
|  | 856 | return NULL; | 
|  | 857 | } | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 858 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 859 | if (_PyVerify_fd(fd)) { | 
|  | 860 | Py_BEGIN_ALLOW_THREADS | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 861 | #if defined(MS_WIN64) || defined(MS_WINDOWS) | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 862 | res = _lseeki64(fd, pos, whence); | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 863 | #else | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 864 | res = lseek(fd, pos, whence); | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 865 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 866 | Py_END_ALLOW_THREADS | 
|  | 867 | } else | 
|  | 868 | res = -1; | 
|  | 869 | if (res < 0) | 
|  | 870 | return PyErr_SetFromErrno(PyExc_IOError); | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 871 |  | 
| Alexandre Vassalotti | 77250f4 | 2008-05-06 19:48:38 +0000 | [diff] [blame] | 872 | #if defined(HAVE_LARGEFILE_SUPPORT) | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 873 | return PyLong_FromLongLong(res); | 
| Alexandre Vassalotti | 77250f4 | 2008-05-06 19:48:38 +0000 | [diff] [blame] | 874 | #else | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 875 | return PyLong_FromLong(res); | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 876 | #endif | 
|  | 877 | } | 
|  | 878 |  | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 879 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 880 | fileio_seek(fileio *self, PyObject *args) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 881 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 882 | PyObject *posobj; | 
|  | 883 | int whence = 0; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 884 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 885 | if (self->fd < 0) | 
|  | 886 | return err_closed(); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 887 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 888 | if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence)) | 
|  | 889 | return NULL; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 890 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 891 | return portable_lseek(self->fd, posobj, whence); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 892 | } | 
|  | 893 |  | 
|  | 894 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 895 | fileio_tell(fileio *self, PyObject *args) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 896 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 897 | if (self->fd < 0) | 
|  | 898 | return err_closed(); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 899 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 900 | return portable_lseek(self->fd, NULL, 1); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 901 | } | 
|  | 902 |  | 
| Thomas Heller | c6a55ee | 2007-07-11 12:45:46 +0000 | [diff] [blame] | 903 | #ifdef HAVE_FTRUNCATE | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 904 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 905 | fileio_truncate(fileio *self, PyObject *args) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 906 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 907 | PyObject *posobj = NULL; /* the new size wanted by the user */ | 
| Antoine Pitrou | 905a2ff | 2010-01-31 22:47:27 +0000 | [diff] [blame] | 908 | #ifndef MS_WINDOWS | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 909 | Py_off_t pos; | 
| Antoine Pitrou | 905a2ff | 2010-01-31 22:47:27 +0000 | [diff] [blame] | 910 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 911 | int ret; | 
|  | 912 | int fd; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 913 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 914 | fd = self->fd; | 
|  | 915 | if (fd < 0) | 
|  | 916 | return err_closed(); | 
|  | 917 | if (!self->writable) | 
|  | 918 | return err_mode("writing"); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 919 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 920 | if (!PyArg_ParseTuple(args, "|O", &posobj)) | 
|  | 921 | return NULL; | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 922 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 923 | if (posobj == Py_None || posobj == NULL) { | 
|  | 924 | /* Get the current position. */ | 
|  | 925 | posobj = portable_lseek(fd, NULL, 1); | 
|  | 926 | if (posobj == NULL) | 
|  | 927 | return NULL; | 
|  | 928 | } | 
|  | 929 | else { | 
|  | 930 | Py_INCREF(posobj); | 
|  | 931 | } | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 932 |  | 
| Thomas Heller | fdeee3a | 2007-07-12 11:21:36 +0000 | [diff] [blame] | 933 | #ifdef MS_WINDOWS | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 934 | /* MS _chsize doesn't work if newsize doesn't fit in 32 bits, | 
|  | 935 | so don't even try using it. */ | 
|  | 936 | { | 
|  | 937 | PyObject *oldposobj, *tempposobj; | 
|  | 938 | HANDLE hFile; | 
| Antoine Pitrou | 905a2ff | 2010-01-31 22:47:27 +0000 | [diff] [blame] | 939 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 940 | /* we save the file pointer position */ | 
|  | 941 | oldposobj = portable_lseek(fd, NULL, 1); | 
|  | 942 | if (oldposobj == NULL) { | 
|  | 943 | Py_DECREF(posobj); | 
|  | 944 | return NULL; | 
|  | 945 | } | 
| Thomas Heller | fdeee3a | 2007-07-12 11:21:36 +0000 | [diff] [blame] | 946 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 947 | /* we then move to the truncation position */ | 
|  | 948 | tempposobj = portable_lseek(fd, posobj, 0); | 
|  | 949 | if (tempposobj == NULL) { | 
|  | 950 | Py_DECREF(oldposobj); | 
|  | 951 | Py_DECREF(posobj); | 
|  | 952 | return NULL; | 
|  | 953 | } | 
|  | 954 | Py_DECREF(tempposobj); | 
| Antoine Pitrou | 905a2ff | 2010-01-31 22:47:27 +0000 | [diff] [blame] | 955 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 956 | /* Truncate.  Note that this may grow the file! */ | 
|  | 957 | Py_BEGIN_ALLOW_THREADS | 
|  | 958 | errno = 0; | 
|  | 959 | hFile = (HANDLE)_get_osfhandle(fd); | 
|  | 960 | ret = hFile == (HANDLE)-1; /* testing for INVALID_HANDLE value */ | 
|  | 961 | if (ret == 0) { | 
|  | 962 | ret = SetEndOfFile(hFile) == 0; | 
|  | 963 | if (ret) | 
|  | 964 | errno = EACCES; | 
|  | 965 | } | 
|  | 966 | Py_END_ALLOW_THREADS | 
|  | 967 |  | 
|  | 968 | /* we restore the file pointer position in any case */ | 
|  | 969 | tempposobj = portable_lseek(fd, oldposobj, 0); | 
|  | 970 | Py_DECREF(oldposobj); | 
|  | 971 | if (tempposobj == NULL) { | 
|  | 972 | Py_DECREF(posobj); | 
|  | 973 | return NULL; | 
|  | 974 | } | 
|  | 975 | Py_DECREF(tempposobj); | 
|  | 976 | } | 
| Thomas Heller | fdeee3a | 2007-07-12 11:21:36 +0000 | [diff] [blame] | 977 | #else | 
| Antoine Pitrou | 905a2ff | 2010-01-31 22:47:27 +0000 | [diff] [blame] | 978 |  | 
|  | 979 | #if defined(HAVE_LARGEFILE_SUPPORT) | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 980 | pos = PyLong_AsLongLong(posobj); | 
| Antoine Pitrou | 905a2ff | 2010-01-31 22:47:27 +0000 | [diff] [blame] | 981 | #else | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 982 | pos = PyLong_AsLong(posobj); | 
| Antoine Pitrou | 905a2ff | 2010-01-31 22:47:27 +0000 | [diff] [blame] | 983 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 984 | if (PyErr_Occurred()){ | 
|  | 985 | Py_DECREF(posobj); | 
|  | 986 | return NULL; | 
|  | 987 | } | 
| Antoine Pitrou | 905a2ff | 2010-01-31 22:47:27 +0000 | [diff] [blame] | 988 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 989 | Py_BEGIN_ALLOW_THREADS | 
|  | 990 | errno = 0; | 
|  | 991 | ret = ftruncate(fd, pos); | 
|  | 992 | Py_END_ALLOW_THREADS | 
| Antoine Pitrou | 905a2ff | 2010-01-31 22:47:27 +0000 | [diff] [blame] | 993 |  | 
| Thomas Heller | fdeee3a | 2007-07-12 11:21:36 +0000 | [diff] [blame] | 994 | #endif /* !MS_WINDOWS */ | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 995 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 996 | if (ret != 0) { | 
|  | 997 | Py_DECREF(posobj); | 
|  | 998 | PyErr_SetFromErrno(PyExc_IOError); | 
|  | 999 | return NULL; | 
|  | 1000 | } | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1001 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1002 | return posobj; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1003 | } | 
| Antoine Pitrou | 905a2ff | 2010-01-31 22:47:27 +0000 | [diff] [blame] | 1004 | #endif /* HAVE_FTRUNCATE */ | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 1005 |  | 
|  | 1006 | static char * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 1007 | mode_string(fileio *self) | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 1008 | { | 
| Charles-François Natali | dc3044c | 2012-01-09 22:40:02 +0100 | [diff] [blame] | 1009 | if (self->created) { | 
|  | 1010 | if (self->readable) | 
|  | 1011 | return "xb+"; | 
|  | 1012 | else | 
|  | 1013 | return "xb"; | 
|  | 1014 | } | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1015 | if (self->readable) { | 
|  | 1016 | if (self->writable) | 
|  | 1017 | return "rb+"; | 
|  | 1018 | else | 
|  | 1019 | return "rb"; | 
|  | 1020 | } | 
|  | 1021 | else | 
|  | 1022 | return "wb"; | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 1023 | } | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1024 |  | 
|  | 1025 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 1026 | fileio_repr(fileio *self) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1027 | { | 
| Martin v. Löwis | 767046a | 2011-10-14 15:35:36 +0200 | [diff] [blame] | 1028 | _Py_IDENTIFIER(name); | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1029 | PyObject *nameobj, *res; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1030 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1031 | if (self->fd < 0) | 
|  | 1032 | return PyUnicode_FromFormat("<_io.FileIO [closed]>"); | 
| Antoine Pitrou | 716c444 | 2009-05-23 19:04:03 +0000 | [diff] [blame] | 1033 |  | 
| Martin v. Löwis | 767046a | 2011-10-14 15:35:36 +0200 | [diff] [blame] | 1034 | nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name); | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1035 | if (nameobj == NULL) { | 
|  | 1036 | if (PyErr_ExceptionMatches(PyExc_AttributeError)) | 
|  | 1037 | PyErr_Clear(); | 
|  | 1038 | else | 
|  | 1039 | return NULL; | 
|  | 1040 | res = PyUnicode_FromFormat("<_io.FileIO fd=%d mode='%s'>", | 
|  | 1041 | self->fd, mode_string(self)); | 
|  | 1042 | } | 
|  | 1043 | else { | 
|  | 1044 | res = PyUnicode_FromFormat("<_io.FileIO name=%R mode='%s'>", | 
|  | 1045 | nameobj, mode_string(self)); | 
|  | 1046 | Py_DECREF(nameobj); | 
|  | 1047 | } | 
|  | 1048 | return res; | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1049 | } | 
|  | 1050 |  | 
|  | 1051 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 1052 | fileio_isatty(fileio *self) | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1053 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1054 | long res; | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 1055 |  | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1056 | if (self->fd < 0) | 
|  | 1057 | return err_closed(); | 
|  | 1058 | Py_BEGIN_ALLOW_THREADS | 
|  | 1059 | res = isatty(self->fd); | 
|  | 1060 | Py_END_ALLOW_THREADS | 
|  | 1061 | return PyBool_FromLong(res); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1062 | } | 
|  | 1063 |  | 
| Antoine Pitrou | 243757e | 2010-11-05 21:15:39 +0000 | [diff] [blame] | 1064 | static PyObject * | 
|  | 1065 | fileio_getstate(fileio *self) | 
|  | 1066 | { | 
|  | 1067 | PyErr_Format(PyExc_TypeError, | 
|  | 1068 | "cannot serialize '%s' object", Py_TYPE(self)->tp_name); | 
|  | 1069 | return NULL; | 
|  | 1070 | } | 
|  | 1071 |  | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1072 |  | 
|  | 1073 | PyDoc_STRVAR(fileio_doc, | 
| Ross Lagerwall | 59142db | 2011-10-31 20:34:46 +0200 | [diff] [blame] | 1074 | "file(name: str[, mode: str][, opener: None]) -> file IO object\n" | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1075 | "\n" | 
| Charles-François Natali | dc3044c | 2012-01-09 22:40:02 +0100 | [diff] [blame] | 1076 | "Open a file.  The mode can be 'r', 'w', 'x' or 'a' for reading (default),\n" | 
| Charles-François Natali | d612de1 | 2012-01-14 11:51:00 +0100 | [diff] [blame] | 1077 | "writing, exclusive creation or appending.  The file will be created if it\n" | 
|  | 1078 | "doesn't exist when opened for writing or appending; it will be truncated\n" | 
|  | 1079 | "when opened for writing.  A `FileExistsError` will be raised if it already\n" | 
| Charles-François Natali | dc3044c | 2012-01-09 22:40:02 +0100 | [diff] [blame] | 1080 | "exists when opened for creating. Opening a file for creating implies\n" | 
|  | 1081 | "writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode\n" | 
|  | 1082 | "to allow simultaneous reading and writing. A custom opener can be used by\n" | 
|  | 1083 | "passing a callable as *opener*. The underlying file descriptor for the file\n" | 
| Ross Lagerwall | 59142db | 2011-10-31 20:34:46 +0200 | [diff] [blame] | 1084 | "object is then obtained by calling opener with (*name*, *flags*).\n" | 
| Charles-François Natali | dc3044c | 2012-01-09 22:40:02 +0100 | [diff] [blame] | 1085 | "*opener* must return an open file descriptor (passing os.open as *opener*\n" | 
|  | 1086 | "results in functionality similar to passing None)."); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1087 |  | 
|  | 1088 | PyDoc_STRVAR(read_doc, | 
|  | 1089 | "read(size: int) -> bytes.  read at most size bytes, returned as bytes.\n" | 
|  | 1090 | "\n" | 
|  | 1091 | "Only makes one system call, so less data may be returned than requested\n" | 
| Guido van Rossum | 7165cb1 | 2007-07-10 06:54:34 +0000 | [diff] [blame] | 1092 | "In non-blocking mode, returns None if no data is available.\n" | 
|  | 1093 | "On end-of-file, returns ''."); | 
|  | 1094 |  | 
|  | 1095 | PyDoc_STRVAR(readall_doc, | 
|  | 1096 | "readall() -> bytes.  read all data from the file, returned as bytes.\n" | 
|  | 1097 | "\n" | 
|  | 1098 | "In non-blocking mode, returns as much as is immediately available,\n" | 
|  | 1099 | "or None if no data is available.  On end-of-file, returns ''."); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1100 |  | 
|  | 1101 | PyDoc_STRVAR(write_doc, | 
|  | 1102 | "write(b: bytes) -> int.  Write bytes b to file, return number written.\n" | 
|  | 1103 | "\n" | 
|  | 1104 | "Only makes one system call, so not all of the data may be written.\n" | 
|  | 1105 | "The number of bytes actually written is returned."); | 
|  | 1106 |  | 
|  | 1107 | PyDoc_STRVAR(fileno_doc, | 
|  | 1108 | "fileno() -> int. \"file descriptor\".\n" | 
|  | 1109 | "\n" | 
|  | 1110 | "This is needed for lower-level file interfaces, such the fcntl module."); | 
|  | 1111 |  | 
|  | 1112 | PyDoc_STRVAR(seek_doc, | 
|  | 1113 | "seek(offset: int[, whence: int]) -> None.  Move to new file position.\n" | 
|  | 1114 | "\n" | 
|  | 1115 | "Argument offset is a byte count.  Optional argument whence defaults to\n" | 
|  | 1116 | "0 (offset from start of file, offset should be >= 0); other values are 1\n" | 
|  | 1117 | "(move relative to current position, positive or negative), and 2 (move\n" | 
|  | 1118 | "relative to end of file, usually negative, although many platforms allow\n" | 
|  | 1119 | "seeking beyond the end of a file)." | 
|  | 1120 | "\n" | 
|  | 1121 | "Note that not all file objects are seekable."); | 
|  | 1122 |  | 
| Thomas Heller | c6a55ee | 2007-07-11 12:45:46 +0000 | [diff] [blame] | 1123 | #ifdef HAVE_FTRUNCATE | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1124 | PyDoc_STRVAR(truncate_doc, | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1125 | "truncate([size: int]) -> None.  Truncate the file to at most size bytes.\n" | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1126 | "\n" | 
| Alexandre Vassalotti | 77250f4 | 2008-05-06 19:48:38 +0000 | [diff] [blame] | 1127 | "Size defaults to the current file position, as returned by tell()." | 
|  | 1128 | "The current file position is changed to the value of size."); | 
| Thomas Heller | c6a55ee | 2007-07-11 12:45:46 +0000 | [diff] [blame] | 1129 | #endif | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1130 |  | 
|  | 1131 | PyDoc_STRVAR(tell_doc, | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1132 | "tell() -> int.  Current file position"); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1133 |  | 
|  | 1134 | PyDoc_STRVAR(readinto_doc, | 
| Benjamin Peterson | 9a8082f | 2009-03-05 00:55:56 +0000 | [diff] [blame] | 1135 | "readinto() -> Same as RawIOBase.readinto()."); | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1136 |  | 
|  | 1137 | PyDoc_STRVAR(close_doc, | 
|  | 1138 | "close() -> None.  Close the file.\n" | 
|  | 1139 | "\n" | 
|  | 1140 | "A closed file cannot be used for further I/O operations.  close() may be\n" | 
|  | 1141 | "called more than once without error.  Changes the fileno to -1."); | 
|  | 1142 |  | 
|  | 1143 | PyDoc_STRVAR(isatty_doc, | 
|  | 1144 | "isatty() -> bool.  True if the file is connected to a tty device."); | 
|  | 1145 |  | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1146 | PyDoc_STRVAR(seekable_doc, | 
|  | 1147 | "seekable() -> bool.  True if file supports random-access."); | 
|  | 1148 |  | 
|  | 1149 | PyDoc_STRVAR(readable_doc, | 
|  | 1150 | "readable() -> bool.  True if file was opened in a read mode."); | 
|  | 1151 |  | 
|  | 1152 | PyDoc_STRVAR(writable_doc, | 
|  | 1153 | "writable() -> bool.  True if file was opened in a write mode."); | 
|  | 1154 |  | 
|  | 1155 | static PyMethodDef fileio_methods[] = { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1156 | {"read",     (PyCFunction)fileio_read,         METH_VARARGS, read_doc}, | 
|  | 1157 | {"readall",  (PyCFunction)fileio_readall,  METH_NOARGS,  readall_doc}, | 
|  | 1158 | {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc}, | 
|  | 1159 | {"write",    (PyCFunction)fileio_write,        METH_VARARGS, write_doc}, | 
|  | 1160 | {"seek",     (PyCFunction)fileio_seek,         METH_VARARGS, seek_doc}, | 
|  | 1161 | {"tell",     (PyCFunction)fileio_tell,         METH_VARARGS, tell_doc}, | 
| Thomas Heller | c6a55ee | 2007-07-11 12:45:46 +0000 | [diff] [blame] | 1162 | #ifdef HAVE_FTRUNCATE | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1163 | {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc}, | 
| Thomas Heller | c6a55ee | 2007-07-11 12:45:46 +0000 | [diff] [blame] | 1164 | #endif | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1165 | {"close",    (PyCFunction)fileio_close,        METH_NOARGS,  close_doc}, | 
|  | 1166 | {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS,      seekable_doc}, | 
|  | 1167 | {"readable", (PyCFunction)fileio_readable, METH_NOARGS,      readable_doc}, | 
|  | 1168 | {"writable", (PyCFunction)fileio_writable, METH_NOARGS,      writable_doc}, | 
|  | 1169 | {"fileno",   (PyCFunction)fileio_fileno,   METH_NOARGS,      fileno_doc}, | 
|  | 1170 | {"isatty",   (PyCFunction)fileio_isatty,   METH_NOARGS,      isatty_doc}, | 
| Antoine Pitrou | e033e06 | 2010-10-29 10:38:18 +0000 | [diff] [blame] | 1171 | {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL}, | 
| Antoine Pitrou | 243757e | 2010-11-05 21:15:39 +0000 | [diff] [blame] | 1172 | {"__getstate__", (PyCFunction)fileio_getstate, METH_NOARGS, NULL}, | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1173 | {NULL,           NULL}             /* sentinel */ | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1174 | }; | 
|  | 1175 |  | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 1176 | /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */ | 
|  | 1177 |  | 
| Guido van Rossum | b042815 | 2007-04-08 17:44:42 +0000 | [diff] [blame] | 1178 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 1179 | get_closed(fileio *self, void *closure) | 
| Guido van Rossum | b042815 | 2007-04-08 17:44:42 +0000 | [diff] [blame] | 1180 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1181 | return PyBool_FromLong((long)(self->fd < 0)); | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 1182 | } | 
|  | 1183 |  | 
|  | 1184 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 1185 | get_closefd(fileio *self, void *closure) | 
| Christian Heimes | ecc42a2 | 2008-11-05 19:30:32 +0000 | [diff] [blame] | 1186 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1187 | return PyBool_FromLong((long)(self->closefd)); | 
| Christian Heimes | ecc42a2 | 2008-11-05 19:30:32 +0000 | [diff] [blame] | 1188 | } | 
|  | 1189 |  | 
|  | 1190 | static PyObject * | 
| Benjamin Peterson | 680bf1a | 2009-06-12 02:07:12 +0000 | [diff] [blame] | 1191 | get_mode(fileio *self, void *closure) | 
| Guido van Rossum | 53807da | 2007-04-10 19:01:47 +0000 | [diff] [blame] | 1192 | { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1193 | return PyUnicode_FromString(mode_string(self)); | 
| Guido van Rossum | b042815 | 2007-04-08 17:44:42 +0000 | [diff] [blame] | 1194 | } | 
|  | 1195 |  | 
|  | 1196 | static PyGetSetDef fileio_getsetlist[] = { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1197 | {"closed", (getter)get_closed, NULL, "True if the file is closed"}, | 
|  | 1198 | {"closefd", (getter)get_closefd, NULL, | 
|  | 1199 | "True if the file descriptor will be closed"}, | 
|  | 1200 | {"mode", (getter)get_mode, NULL, "String giving the file mode"}, | 
|  | 1201 | {NULL}, | 
| Guido van Rossum | b042815 | 2007-04-08 17:44:42 +0000 | [diff] [blame] | 1202 | }; | 
|  | 1203 |  | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1204 | PyTypeObject PyFileIO_Type = { | 
| Antoine Pitrou | ae4b472 | 2010-05-05 16:31:07 +0000 | [diff] [blame] | 1205 | PyVarObject_HEAD_INIT(NULL, 0) | 
|  | 1206 | "_io.FileIO", | 
|  | 1207 | sizeof(fileio), | 
|  | 1208 | 0, | 
|  | 1209 | (destructor)fileio_dealloc,                 /* tp_dealloc */ | 
|  | 1210 | 0,                                          /* tp_print */ | 
|  | 1211 | 0,                                          /* tp_getattr */ | 
|  | 1212 | 0,                                          /* tp_setattr */ | 
|  | 1213 | 0,                                          /* tp_reserved */ | 
|  | 1214 | (reprfunc)fileio_repr,                      /* tp_repr */ | 
|  | 1215 | 0,                                          /* tp_as_number */ | 
|  | 1216 | 0,                                          /* tp_as_sequence */ | 
|  | 1217 | 0,                                          /* tp_as_mapping */ | 
|  | 1218 | 0,                                          /* tp_hash */ | 
|  | 1219 | 0,                                          /* tp_call */ | 
|  | 1220 | 0,                                          /* tp_str */ | 
|  | 1221 | PyObject_GenericGetAttr,                    /* tp_getattro */ | 
|  | 1222 | 0,                                          /* tp_setattro */ | 
|  | 1223 | 0,                                          /* tp_as_buffer */ | 
|  | 1224 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | 
|  | 1225 | | Py_TPFLAGS_HAVE_GC,       /* tp_flags */ | 
|  | 1226 | fileio_doc,                                 /* tp_doc */ | 
|  | 1227 | (traverseproc)fileio_traverse,              /* tp_traverse */ | 
|  | 1228 | (inquiry)fileio_clear,                      /* tp_clear */ | 
|  | 1229 | 0,                                          /* tp_richcompare */ | 
|  | 1230 | offsetof(fileio, weakreflist),      /* tp_weaklistoffset */ | 
|  | 1231 | 0,                                          /* tp_iter */ | 
|  | 1232 | 0,                                          /* tp_iternext */ | 
|  | 1233 | fileio_methods,                             /* tp_methods */ | 
|  | 1234 | 0,                                          /* tp_members */ | 
|  | 1235 | fileio_getsetlist,                          /* tp_getset */ | 
|  | 1236 | 0,                                          /* tp_base */ | 
|  | 1237 | 0,                                          /* tp_dict */ | 
|  | 1238 | 0,                                          /* tp_descr_get */ | 
|  | 1239 | 0,                                          /* tp_descr_set */ | 
|  | 1240 | offsetof(fileio, dict),         /* tp_dictoffset */ | 
|  | 1241 | fileio_init,                                /* tp_init */ | 
|  | 1242 | PyType_GenericAlloc,                        /* tp_alloc */ | 
|  | 1243 | fileio_new,                                 /* tp_new */ | 
|  | 1244 | PyObject_GC_Del,                            /* tp_free */ | 
| Guido van Rossum | a9e2024 | 2007-03-08 00:43:48 +0000 | [diff] [blame] | 1245 | }; |