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