/src/Python-3.8.3/Modules/_io/fileio.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Author: Daniel Stutzbach */ |
2 | | |
3 | | #define PY_SSIZE_T_CLEAN |
4 | | #include "Python.h" |
5 | | #include "pycore_object.h" |
6 | | #include "structmember.h" |
7 | | #include <stdbool.h> |
8 | | #ifdef HAVE_SYS_TYPES_H |
9 | | #include <sys/types.h> |
10 | | #endif |
11 | | #ifdef HAVE_SYS_STAT_H |
12 | | #include <sys/stat.h> |
13 | | #endif |
14 | | #ifdef HAVE_IO_H |
15 | | #include <io.h> |
16 | | #endif |
17 | | #ifdef HAVE_FCNTL_H |
18 | | #include <fcntl.h> |
19 | | #endif |
20 | | #include <stddef.h> /* For offsetof */ |
21 | | #include "_iomodule.h" |
22 | | |
23 | | /* |
24 | | * Known likely problems: |
25 | | * |
26 | | * - Files larger then 2**32-1 |
27 | | * - Files with unicode filenames |
28 | | * - Passing numbers greater than 2**32-1 when an integer is expected |
29 | | * - Making it work on Windows and other oddball platforms |
30 | | * |
31 | | * To Do: |
32 | | * |
33 | | * - autoconfify header file inclusion |
34 | | */ |
35 | | |
36 | | #ifdef MS_WINDOWS |
37 | | /* can simulate truncate with Win32 API functions; see file_truncate */ |
38 | | #define HAVE_FTRUNCATE |
39 | | #define WIN32_LEAN_AND_MEAN |
40 | | #include <windows.h> |
41 | | #endif |
42 | | |
43 | | #if BUFSIZ < (8*1024) |
44 | | #define SMALLCHUNK (8*1024) |
45 | | #elif (BUFSIZ >= (2 << 25)) |
46 | | #error "unreasonable BUFSIZ > 64 MiB defined" |
47 | | #else |
48 | 0 | #define SMALLCHUNK BUFSIZ |
49 | | #endif |
50 | | |
51 | | /*[clinic input] |
52 | | module _io |
53 | | class _io.FileIO "fileio *" "&PyFileIO_Type" |
54 | | [clinic start generated code]*/ |
55 | | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=1c77708b41fda70c]*/ |
56 | | |
57 | | typedef struct { |
58 | | PyObject_HEAD |
59 | | int fd; |
60 | | unsigned int created : 1; |
61 | | unsigned int readable : 1; |
62 | | unsigned int writable : 1; |
63 | | unsigned int appending : 1; |
64 | | signed int seekable : 2; /* -1 means unknown */ |
65 | | unsigned int closefd : 1; |
66 | | char finalizing; |
67 | | unsigned int blksize; |
68 | | PyObject *weakreflist; |
69 | | PyObject *dict; |
70 | | } fileio; |
71 | | |
72 | | PyTypeObject PyFileIO_Type; |
73 | | |
74 | | _Py_IDENTIFIER(name); |
75 | | |
76 | | #define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type)) |
77 | | |
78 | | /* Forward declarations */ |
79 | | static PyObject* portable_lseek(fileio *self, PyObject *posobj, int whence, bool suppress_pipe_error); |
80 | | |
81 | | int |
82 | | _PyFileIO_closed(PyObject *self) |
83 | 558 | { |
84 | 558 | return ((fileio *)self)->fd < 0; |
85 | 558 | } |
86 | | |
87 | | /* Because this can call arbitrary code, it shouldn't be called when |
88 | | the refcount is 0 (that is, not directly from tp_dealloc unless |
89 | | the refcount has been temporarily re-incremented). */ |
90 | | static PyObject * |
91 | | fileio_dealloc_warn(fileio *self, PyObject *source) |
92 | 0 | { |
93 | 0 | if (self->fd >= 0 && self->closefd) { |
94 | 0 | PyObject *exc, *val, *tb; |
95 | 0 | PyErr_Fetch(&exc, &val, &tb); |
96 | 0 | if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) { |
97 | | /* Spurious errors can appear at shutdown */ |
98 | 0 | if (PyErr_ExceptionMatches(PyExc_Warning)) |
99 | 0 | PyErr_WriteUnraisable((PyObject *) self); |
100 | 0 | } |
101 | 0 | PyErr_Restore(exc, val, tb); |
102 | 0 | } |
103 | 0 | Py_RETURN_NONE; |
104 | 0 | } |
105 | | |
106 | | /* Returns 0 on success, -1 with exception set on failure. */ |
107 | | static int |
108 | | internal_close(fileio *self) |
109 | 236 | { |
110 | 236 | int err = 0; |
111 | 236 | int save_errno = 0; |
112 | 236 | if (self->fd >= 0) { |
113 | 236 | int fd = self->fd; |
114 | 236 | self->fd = -1; |
115 | | /* fd is accessible and someone else may have closed it */ |
116 | 236 | Py_BEGIN_ALLOW_THREADS |
117 | 236 | _Py_BEGIN_SUPPRESS_IPH |
118 | 236 | err = close(fd); |
119 | 236 | if (err < 0) |
120 | 0 | save_errno = errno; |
121 | 236 | _Py_END_SUPPRESS_IPH |
122 | 236 | Py_END_ALLOW_THREADS |
123 | 236 | } |
124 | 236 | if (err < 0) { |
125 | 0 | errno = save_errno; |
126 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
127 | 0 | return -1; |
128 | 0 | } |
129 | 236 | return 0; |
130 | 236 | } |
131 | | |
132 | | /*[clinic input] |
133 | | _io.FileIO.close |
134 | | |
135 | | Close the file. |
136 | | |
137 | | A closed file cannot be used for further I/O operations. close() may be |
138 | | called more than once without error. |
139 | | [clinic start generated code]*/ |
140 | | |
141 | | static PyObject * |
142 | | _io_FileIO_close_impl(fileio *self) |
143 | | /*[clinic end generated code: output=7737a319ef3bad0b input=f35231760d54a522]*/ |
144 | 236 | { |
145 | 236 | PyObject *res; |
146 | 236 | PyObject *exc, *val, *tb; |
147 | 236 | int rc; |
148 | 236 | _Py_IDENTIFIER(close); |
149 | 236 | res = _PyObject_CallMethodIdObjArgs((PyObject*)&PyRawIOBase_Type, |
150 | 236 | &PyId_close, self, NULL); |
151 | 236 | if (!self->closefd) { |
152 | 0 | self->fd = -1; |
153 | 0 | return res; |
154 | 0 | } |
155 | 236 | if (res == NULL) |
156 | 0 | PyErr_Fetch(&exc, &val, &tb); |
157 | 236 | if (self->finalizing) { |
158 | 0 | PyObject *r = fileio_dealloc_warn(self, (PyObject *) self); |
159 | 0 | if (r) |
160 | 0 | Py_DECREF(r); |
161 | 0 | else |
162 | 0 | PyErr_Clear(); |
163 | 0 | } |
164 | 236 | rc = internal_close(self); |
165 | 236 | if (res == NULL) |
166 | 0 | _PyErr_ChainExceptions(exc, val, tb); |
167 | 236 | if (rc < 0) |
168 | 0 | Py_CLEAR(res); |
169 | 236 | return res; |
170 | 236 | } |
171 | | |
172 | | static PyObject * |
173 | | fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
174 | 278 | { |
175 | 278 | fileio *self; |
176 | | |
177 | 278 | assert(type != NULL && type->tp_alloc != NULL); |
178 | | |
179 | 278 | self = (fileio *) type->tp_alloc(type, 0); |
180 | 278 | if (self != NULL) { |
181 | 278 | self->fd = -1; |
182 | 278 | self->created = 0; |
183 | 278 | self->readable = 0; |
184 | 278 | self->writable = 0; |
185 | 278 | self->appending = 0; |
186 | 278 | self->seekable = -1; |
187 | 278 | self->blksize = 0; |
188 | 278 | self->closefd = 1; |
189 | 278 | self->weakreflist = NULL; |
190 | 278 | } |
191 | | |
192 | 278 | return (PyObject *) self; |
193 | 278 | } |
194 | | |
195 | | #ifdef O_CLOEXEC |
196 | | extern int _Py_open_cloexec_works; |
197 | | #endif |
198 | | |
199 | | /*[clinic input] |
200 | | _io.FileIO.__init__ |
201 | | file as nameobj: object |
202 | | mode: str = "r" |
203 | | closefd: bool(accept={int}) = True |
204 | | opener: object = None |
205 | | |
206 | | Open a file. |
207 | | |
208 | | The mode can be 'r' (default), 'w', 'x' or 'a' for reading, |
209 | | writing, exclusive creation or appending. The file will be created if it |
210 | | doesn't exist when opened for writing or appending; it will be truncated |
211 | | when opened for writing. A FileExistsError will be raised if it already |
212 | | exists when opened for creating. Opening a file for creating implies |
213 | | writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode |
214 | | to allow simultaneous reading and writing. A custom opener can be used by |
215 | | passing a callable as *opener*. The underlying file descriptor for the file |
216 | | object is then obtained by calling opener with (*name*, *flags*). |
217 | | *opener* must return an open file descriptor (passing os.open as *opener* |
218 | | results in functionality similar to passing None). |
219 | | [clinic start generated code]*/ |
220 | | |
221 | | static int |
222 | | _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, |
223 | | int closefd, PyObject *opener) |
224 | | /*[clinic end generated code: output=23413f68e6484bbd input=1596c9157a042a39]*/ |
225 | 278 | { |
226 | | #ifdef MS_WINDOWS |
227 | | Py_UNICODE *widename = NULL; |
228 | | #else |
229 | 278 | const char *name = NULL; |
230 | 278 | #endif |
231 | 278 | PyObject *stringobj = NULL; |
232 | 278 | const char *s; |
233 | 278 | int ret = 0; |
234 | 278 | int rwa = 0, plus = 0; |
235 | 278 | int flags = 0; |
236 | 278 | int fd = -1; |
237 | 278 | int fd_is_own = 0; |
238 | 278 | #ifdef O_CLOEXEC |
239 | 278 | int *atomic_flag_works = &_Py_open_cloexec_works; |
240 | | #elif !defined(MS_WINDOWS) |
241 | | int *atomic_flag_works = NULL; |
242 | | #endif |
243 | 278 | struct _Py_stat_struct fdfstat; |
244 | 278 | int fstat_result; |
245 | 278 | int async_err = 0; |
246 | | |
247 | 278 | assert(PyFileIO_Check(self)); |
248 | 278 | if (self->fd >= 0) { |
249 | 0 | if (self->closefd) { |
250 | | /* Have to close the existing file first. */ |
251 | 0 | if (internal_close(self) < 0) |
252 | 0 | return -1; |
253 | 0 | } |
254 | 0 | else |
255 | 0 | self->fd = -1; |
256 | 0 | } |
257 | | |
258 | 278 | if (PyFloat_Check(nameobj)) { |
259 | 0 | PyErr_SetString(PyExc_TypeError, |
260 | 0 | "integer argument expected, got float"); |
261 | 0 | return -1; |
262 | 0 | } |
263 | | |
264 | 278 | fd = _PyLong_AsInt(nameobj); |
265 | 278 | if (fd < 0) { |
266 | 236 | if (!PyErr_Occurred()) { |
267 | 0 | PyErr_SetString(PyExc_ValueError, |
268 | 0 | "negative file descriptor"); |
269 | 0 | return -1; |
270 | 0 | } |
271 | 236 | PyErr_Clear(); |
272 | 236 | } |
273 | | |
274 | 278 | if (fd < 0) { |
275 | | #ifdef MS_WINDOWS |
276 | | if (!PyUnicode_FSDecoder(nameobj, &stringobj)) { |
277 | | return -1; |
278 | | } |
279 | | widename = PyUnicode_AsUnicode(stringobj); |
280 | | if (widename == NULL) |
281 | | return -1; |
282 | | #else |
283 | 236 | if (!PyUnicode_FSConverter(nameobj, &stringobj)) { |
284 | 0 | return -1; |
285 | 0 | } |
286 | 236 | name = PyBytes_AS_STRING(stringobj); |
287 | 236 | #endif |
288 | 236 | } |
289 | | |
290 | 278 | s = mode; |
291 | 556 | while (*s) { |
292 | 278 | switch (*s++) { |
293 | 0 | case 'x': |
294 | 0 | if (rwa) { |
295 | 0 | bad_mode: |
296 | 0 | PyErr_SetString(PyExc_ValueError, |
297 | 0 | "Must have exactly one of create/read/write/append " |
298 | 0 | "mode and at most one plus"); |
299 | 0 | goto error; |
300 | 0 | } |
301 | 0 | rwa = 1; |
302 | 0 | self->created = 1; |
303 | 0 | self->writable = 1; |
304 | 0 | flags |= O_EXCL | O_CREAT; |
305 | 0 | break; |
306 | 250 | case 'r': |
307 | 250 | if (rwa) |
308 | 0 | goto bad_mode; |
309 | 250 | rwa = 1; |
310 | 250 | self->readable = 1; |
311 | 250 | break; |
312 | 28 | case 'w': |
313 | 28 | if (rwa) |
314 | 0 | goto bad_mode; |
315 | 28 | rwa = 1; |
316 | 28 | self->writable = 1; |
317 | 28 | flags |= O_CREAT | O_TRUNC; |
318 | 28 | break; |
319 | 0 | case 'a': |
320 | 0 | if (rwa) |
321 | 0 | goto bad_mode; |
322 | 0 | rwa = 1; |
323 | 0 | self->writable = 1; |
324 | 0 | self->appending = 1; |
325 | 0 | flags |= O_APPEND | O_CREAT; |
326 | 0 | break; |
327 | 0 | case 'b': |
328 | 0 | break; |
329 | 0 | case '+': |
330 | 0 | if (plus) |
331 | 0 | goto bad_mode; |
332 | 0 | self->readable = self->writable = 1; |
333 | 0 | plus = 1; |
334 | 0 | break; |
335 | 0 | default: |
336 | 0 | PyErr_Format(PyExc_ValueError, |
337 | 0 | "invalid mode: %.200s", mode); |
338 | 0 | goto error; |
339 | 278 | } |
340 | 278 | } |
341 | | |
342 | 278 | if (!rwa) |
343 | 0 | goto bad_mode; |
344 | | |
345 | 278 | if (self->readable && self->writable) |
346 | 0 | flags |= O_RDWR; |
347 | 278 | else if (self->readable) |
348 | 250 | flags |= O_RDONLY; |
349 | 28 | else |
350 | 28 | flags |= O_WRONLY; |
351 | | |
352 | | #ifdef O_BINARY |
353 | | flags |= O_BINARY; |
354 | | #endif |
355 | | |
356 | | #ifdef MS_WINDOWS |
357 | | flags |= O_NOINHERIT; |
358 | | #elif defined(O_CLOEXEC) |
359 | | flags |= O_CLOEXEC; |
360 | 278 | #endif |
361 | | |
362 | 278 | if (PySys_Audit("open", "Osi", nameobj, mode, flags) < 0) { |
363 | 0 | goto error; |
364 | 0 | } |
365 | | |
366 | 278 | if (fd >= 0) { |
367 | 42 | self->fd = fd; |
368 | 42 | self->closefd = closefd; |
369 | 42 | } |
370 | 236 | else { |
371 | 236 | self->closefd = 1; |
372 | 236 | if (!closefd) { |
373 | 0 | PyErr_SetString(PyExc_ValueError, |
374 | 0 | "Cannot use closefd=False with file name"); |
375 | 0 | goto error; |
376 | 0 | } |
377 | | |
378 | 236 | errno = 0; |
379 | 236 | if (opener == Py_None) { |
380 | 236 | do { |
381 | 236 | Py_BEGIN_ALLOW_THREADS |
382 | | #ifdef MS_WINDOWS |
383 | | self->fd = _wopen(widename, flags, 0666); |
384 | | #else |
385 | 236 | self->fd = open(name, flags, 0666); |
386 | 236 | #endif |
387 | 236 | Py_END_ALLOW_THREADS |
388 | 236 | } while (self->fd < 0 && errno == EINTR && |
389 | 236 | !(async_err = PyErr_CheckSignals())); |
390 | | |
391 | 236 | if (async_err) |
392 | 0 | goto error; |
393 | 236 | } |
394 | 0 | else { |
395 | 0 | PyObject *fdobj; |
396 | |
|
397 | 0 | #ifndef MS_WINDOWS |
398 | | /* the opener may clear the atomic flag */ |
399 | 0 | atomic_flag_works = NULL; |
400 | 0 | #endif |
401 | |
|
402 | 0 | fdobj = PyObject_CallFunction(opener, "Oi", nameobj, flags); |
403 | 0 | if (fdobj == NULL) |
404 | 0 | goto error; |
405 | 0 | if (!PyLong_Check(fdobj)) { |
406 | 0 | Py_DECREF(fdobj); |
407 | 0 | PyErr_SetString(PyExc_TypeError, |
408 | 0 | "expected integer from opener"); |
409 | 0 | goto error; |
410 | 0 | } |
411 | | |
412 | 0 | self->fd = _PyLong_AsInt(fdobj); |
413 | 0 | Py_DECREF(fdobj); |
414 | 0 | if (self->fd < 0) { |
415 | 0 | if (!PyErr_Occurred()) { |
416 | | /* The opener returned a negative but didn't set an |
417 | | exception. See issue #27066 */ |
418 | 0 | PyErr_Format(PyExc_ValueError, |
419 | 0 | "opener returned %d", self->fd); |
420 | 0 | } |
421 | 0 | goto error; |
422 | 0 | } |
423 | 0 | } |
424 | | |
425 | 236 | fd_is_own = 1; |
426 | 236 | if (self->fd < 0) { |
427 | 0 | PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); |
428 | 0 | goto error; |
429 | 0 | } |
430 | | |
431 | 236 | #ifndef MS_WINDOWS |
432 | 236 | if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0) |
433 | 0 | goto error; |
434 | 236 | #endif |
435 | 236 | } |
436 | | |
437 | 278 | self->blksize = DEFAULT_BUFFER_SIZE; |
438 | 278 | Py_BEGIN_ALLOW_THREADS |
439 | 278 | fstat_result = _Py_fstat_noraise(self->fd, &fdfstat); |
440 | 278 | Py_END_ALLOW_THREADS |
441 | 278 | if (fstat_result < 0) { |
442 | | /* Tolerate fstat() errors other than EBADF. See Issue #25717, where |
443 | | an anonymous file on a Virtual Box shared folder filesystem would |
444 | | raise ENOENT. */ |
445 | | #ifdef MS_WINDOWS |
446 | | if (GetLastError() == ERROR_INVALID_HANDLE) { |
447 | | PyErr_SetFromWindowsErr(0); |
448 | | #else |
449 | 0 | if (errno == EBADF) { |
450 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
451 | 0 | #endif |
452 | 0 | goto error; |
453 | 0 | } |
454 | 0 | } |
455 | 278 | else { |
456 | 278 | #if defined(S_ISDIR) && defined(EISDIR) |
457 | | /* On Unix, open will succeed for directories. |
458 | | In Python, there should be no file objects referring to |
459 | | directories, so we need a check. */ |
460 | 278 | if (S_ISDIR(fdfstat.st_mode)) { |
461 | 0 | errno = EISDIR; |
462 | 0 | PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); |
463 | 0 | goto error; |
464 | 0 | } |
465 | 278 | #endif /* defined(S_ISDIR) */ |
466 | 278 | #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE |
467 | 278 | if (fdfstat.st_blksize > 1) |
468 | 278 | self->blksize = fdfstat.st_blksize; |
469 | 278 | #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ |
470 | 278 | } |
471 | | |
472 | | #if defined(MS_WINDOWS) || defined(__CYGWIN__) |
473 | | /* don't translate newlines (\r\n <=> \n) */ |
474 | | _setmode(self->fd, O_BINARY); |
475 | | #endif |
476 | | |
477 | 278 | if (_PyObject_SetAttrId((PyObject *)self, &PyId_name, nameobj) < 0) |
478 | 0 | goto error; |
479 | | |
480 | 278 | if (self->appending) { |
481 | | /* For consistent behaviour, we explicitly seek to the |
482 | | end of file (otherwise, it might be done only on the |
483 | | first write()). */ |
484 | 0 | PyObject *pos = portable_lseek(self, NULL, 2, true); |
485 | 0 | if (pos == NULL) |
486 | 0 | goto error; |
487 | 0 | Py_DECREF(pos); |
488 | 0 | } |
489 | | |
490 | 278 | goto done; |
491 | | |
492 | 278 | error: |
493 | 0 | ret = -1; |
494 | 0 | if (!fd_is_own) |
495 | 0 | self->fd = -1; |
496 | 0 | if (self->fd >= 0) |
497 | 0 | internal_close(self); |
498 | |
|
499 | 278 | done: |
500 | 278 | Py_CLEAR(stringobj); |
501 | 278 | return ret; |
502 | 0 | } |
503 | | |
504 | | static int |
505 | | fileio_traverse(fileio *self, visitproc visit, void *arg) |
506 | 90 | { |
507 | 90 | Py_VISIT(self->dict); |
508 | 90 | return 0; |
509 | 90 | } |
510 | | |
511 | | static int |
512 | | fileio_clear(fileio *self) |
513 | 0 | { |
514 | 0 | Py_CLEAR(self->dict); |
515 | 0 | return 0; |
516 | 0 | } |
517 | | |
518 | | static void |
519 | | fileio_dealloc(fileio *self) |
520 | 236 | { |
521 | 236 | self->finalizing = 1; |
522 | 236 | if (_PyIOBase_finalize((PyObject *) self) < 0) |
523 | 0 | return; |
524 | 236 | _PyObject_GC_UNTRACK(self); |
525 | 236 | if (self->weakreflist != NULL) |
526 | 0 | PyObject_ClearWeakRefs((PyObject *) self); |
527 | 236 | Py_CLEAR(self->dict); |
528 | 236 | Py_TYPE(self)->tp_free((PyObject *)self); |
529 | 236 | } |
530 | | |
531 | | static PyObject * |
532 | | err_closed(void) |
533 | 0 | { |
534 | 0 | PyErr_SetString(PyExc_ValueError, "I/O operation on closed file"); |
535 | 0 | return NULL; |
536 | 0 | } |
537 | | |
538 | | static PyObject * |
539 | | err_mode(const char *action) |
540 | 0 | { |
541 | 0 | _PyIO_State *state = IO_STATE(); |
542 | 0 | if (state != NULL) |
543 | 0 | PyErr_Format(state->unsupported_operation, |
544 | 0 | "File not open for %s", action); |
545 | 0 | return NULL; |
546 | 0 | } |
547 | | |
548 | | /*[clinic input] |
549 | | _io.FileIO.fileno |
550 | | |
551 | | Return the underlying file descriptor (an integer). |
552 | | [clinic start generated code]*/ |
553 | | |
554 | | static PyObject * |
555 | | _io_FileIO_fileno_impl(fileio *self) |
556 | | /*[clinic end generated code: output=a9626ce5398ece90 input=0b9b2de67335ada3]*/ |
557 | 0 | { |
558 | 0 | if (self->fd < 0) |
559 | 0 | return err_closed(); |
560 | 0 | return PyLong_FromLong((long) self->fd); |
561 | 0 | } |
562 | | |
563 | | /*[clinic input] |
564 | | _io.FileIO.readable |
565 | | |
566 | | True if file was opened in a read mode. |
567 | | [clinic start generated code]*/ |
568 | | |
569 | | static PyObject * |
570 | | _io_FileIO_readable_impl(fileio *self) |
571 | | /*[clinic end generated code: output=640744a6150fe9ba input=a3fdfed6eea721c5]*/ |
572 | 265 | { |
573 | 265 | if (self->fd < 0) |
574 | 0 | return err_closed(); |
575 | 265 | return PyBool_FromLong((long) self->readable); |
576 | 265 | } |
577 | | |
578 | | /*[clinic input] |
579 | | _io.FileIO.writable |
580 | | |
581 | | True if file was opened in a write mode. |
582 | | [clinic start generated code]*/ |
583 | | |
584 | | static PyObject * |
585 | | _io_FileIO_writable_impl(fileio *self) |
586 | | /*[clinic end generated code: output=96cefc5446e89977 input=c204a808ca2e1748]*/ |
587 | 56 | { |
588 | 56 | if (self->fd < 0) |
589 | 0 | return err_closed(); |
590 | 56 | return PyBool_FromLong((long) self->writable); |
591 | 56 | } |
592 | | |
593 | | /*[clinic input] |
594 | | _io.FileIO.seekable |
595 | | |
596 | | True if file supports random-access. |
597 | | [clinic start generated code]*/ |
598 | | |
599 | | static PyObject * |
600 | | _io_FileIO_seekable_impl(fileio *self) |
601 | | /*[clinic end generated code: output=47909ca0a42e9287 input=c8e5554d2fd63c7f]*/ |
602 | 44 | { |
603 | 44 | if (self->fd < 0) |
604 | 0 | return err_closed(); |
605 | 44 | if (self->seekable < 0) { |
606 | | /* portable_lseek() sets the seekable attribute */ |
607 | 0 | PyObject *pos = portable_lseek(self, NULL, SEEK_CUR, false); |
608 | 0 | assert(self->seekable >= 0); |
609 | 0 | if (pos == NULL) { |
610 | 0 | PyErr_Clear(); |
611 | 0 | } |
612 | 0 | else { |
613 | 0 | Py_DECREF(pos); |
614 | 0 | } |
615 | 0 | } |
616 | 44 | return PyBool_FromLong((long) self->seekable); |
617 | 44 | } |
618 | | |
619 | | /*[clinic input] |
620 | | _io.FileIO.readinto |
621 | | buffer: Py_buffer(accept={rwbuffer}) |
622 | | / |
623 | | |
624 | | Same as RawIOBase.readinto(). |
625 | | [clinic start generated code]*/ |
626 | | |
627 | | static PyObject * |
628 | | _io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer) |
629 | | /*[clinic end generated code: output=b01a5a22c8415cb4 input=4721d7b68b154eaf]*/ |
630 | 3 | { |
631 | 3 | Py_ssize_t n; |
632 | 3 | int err; |
633 | | |
634 | 3 | if (self->fd < 0) |
635 | 0 | return err_closed(); |
636 | 3 | if (!self->readable) |
637 | 0 | return err_mode("reading"); |
638 | | |
639 | 3 | n = _Py_read(self->fd, buffer->buf, buffer->len); |
640 | | /* copy errno because PyBuffer_Release() can indirectly modify it */ |
641 | 3 | err = errno; |
642 | | |
643 | 3 | if (n == -1) { |
644 | 0 | if (err == EAGAIN) { |
645 | 0 | PyErr_Clear(); |
646 | 0 | Py_RETURN_NONE; |
647 | 0 | } |
648 | 0 | return NULL; |
649 | 0 | } |
650 | | |
651 | 3 | return PyLong_FromSsize_t(n); |
652 | 3 | } |
653 | | |
654 | | static size_t |
655 | | new_buffersize(fileio *self, size_t currentsize) |
656 | 0 | { |
657 | 0 | size_t addend; |
658 | | |
659 | | /* Expand the buffer by an amount proportional to the current size, |
660 | | giving us amortized linear-time behavior. For bigger sizes, use a |
661 | | less-than-double growth factor to avoid excessive allocation. */ |
662 | 0 | assert(currentsize <= PY_SSIZE_T_MAX); |
663 | 0 | if (currentsize > 65536) |
664 | 0 | addend = currentsize >> 3; |
665 | 0 | else |
666 | 0 | addend = 256 + currentsize; |
667 | 0 | if (addend < SMALLCHUNK) |
668 | | /* Avoid tiny read() calls. */ |
669 | 0 | addend = SMALLCHUNK; |
670 | 0 | return addend + currentsize; |
671 | 0 | } |
672 | | |
673 | | /*[clinic input] |
674 | | _io.FileIO.readall |
675 | | |
676 | | Read all data from the file, returned as bytes. |
677 | | |
678 | | In non-blocking mode, returns as much as is immediately available, |
679 | | or None if no data is available. Return an empty bytes object at EOF. |
680 | | [clinic start generated code]*/ |
681 | | |
682 | | static PyObject * |
683 | | _io_FileIO_readall_impl(fileio *self) |
684 | | /*[clinic end generated code: output=faa0292b213b4022 input=dbdc137f55602834]*/ |
685 | 235 | { |
686 | 235 | struct _Py_stat_struct status; |
687 | 235 | Py_off_t pos, end; |
688 | 235 | PyObject *result; |
689 | 235 | Py_ssize_t bytes_read = 0; |
690 | 235 | Py_ssize_t n; |
691 | 235 | size_t bufsize; |
692 | 235 | int fstat_result; |
693 | | |
694 | 235 | if (self->fd < 0) |
695 | 0 | return err_closed(); |
696 | | |
697 | 235 | Py_BEGIN_ALLOW_THREADS |
698 | 235 | _Py_BEGIN_SUPPRESS_IPH |
699 | | #ifdef MS_WINDOWS |
700 | | pos = _lseeki64(self->fd, 0L, SEEK_CUR); |
701 | | #else |
702 | 235 | pos = lseek(self->fd, 0L, SEEK_CUR); |
703 | 235 | #endif |
704 | 235 | _Py_END_SUPPRESS_IPH |
705 | 235 | fstat_result = _Py_fstat_noraise(self->fd, &status); |
706 | 235 | Py_END_ALLOW_THREADS |
707 | | |
708 | 235 | if (fstat_result == 0) |
709 | 235 | end = status.st_size; |
710 | 0 | else |
711 | 0 | end = (Py_off_t)-1; |
712 | | |
713 | 235 | if (end > 0 && end >= pos && pos >= 0 && end - pos < PY_SSIZE_T_MAX) { |
714 | | /* This is probably a real file, so we try to allocate a |
715 | | buffer one byte larger than the rest of the file. If the |
716 | | calculation is right then we should get EOF without having |
717 | | to enlarge the buffer. */ |
718 | 235 | bufsize = (size_t)(end - pos + 1); |
719 | 235 | } else { |
720 | 0 | bufsize = SMALLCHUNK; |
721 | 0 | } |
722 | | |
723 | 235 | result = PyBytes_FromStringAndSize(NULL, bufsize); |
724 | 235 | if (result == NULL) |
725 | 0 | return NULL; |
726 | | |
727 | 470 | while (1) { |
728 | 470 | if (bytes_read >= (Py_ssize_t)bufsize) { |
729 | 0 | bufsize = new_buffersize(self, bytes_read); |
730 | 0 | if (bufsize > PY_SSIZE_T_MAX || bufsize <= 0) { |
731 | 0 | PyErr_SetString(PyExc_OverflowError, |
732 | 0 | "unbounded read returned more bytes " |
733 | 0 | "than a Python bytes object can hold"); |
734 | 0 | Py_DECREF(result); |
735 | 0 | return NULL; |
736 | 0 | } |
737 | | |
738 | 0 | if (PyBytes_GET_SIZE(result) < (Py_ssize_t)bufsize) { |
739 | 0 | if (_PyBytes_Resize(&result, bufsize) < 0) |
740 | 0 | return NULL; |
741 | 0 | } |
742 | 0 | } |
743 | | |
744 | 470 | n = _Py_read(self->fd, |
745 | 470 | PyBytes_AS_STRING(result) + bytes_read, |
746 | 470 | bufsize - bytes_read); |
747 | | |
748 | 470 | if (n == 0) |
749 | 235 | break; |
750 | 235 | if (n == -1) { |
751 | 0 | if (errno == EAGAIN) { |
752 | 0 | PyErr_Clear(); |
753 | 0 | if (bytes_read > 0) |
754 | 0 | break; |
755 | 0 | Py_DECREF(result); |
756 | 0 | Py_RETURN_NONE; |
757 | 0 | } |
758 | 0 | Py_DECREF(result); |
759 | 0 | return NULL; |
760 | 0 | } |
761 | 235 | bytes_read += n; |
762 | 235 | pos += n; |
763 | 235 | } |
764 | | |
765 | 235 | if (PyBytes_GET_SIZE(result) > bytes_read) { |
766 | 235 | if (_PyBytes_Resize(&result, bytes_read) < 0) |
767 | 0 | return NULL; |
768 | 235 | } |
769 | 235 | return result; |
770 | 235 | } |
771 | | |
772 | | /*[clinic input] |
773 | | _io.FileIO.read |
774 | | size: Py_ssize_t(accept={int, NoneType}) = -1 |
775 | | / |
776 | | |
777 | | Read at most size bytes, returned as bytes. |
778 | | |
779 | | Only makes one system call, so less data may be returned than requested. |
780 | | In non-blocking mode, returns None if no data is available. |
781 | | Return an empty bytes object at EOF. |
782 | | [clinic start generated code]*/ |
783 | | |
784 | | static PyObject * |
785 | | _io_FileIO_read_impl(fileio *self, Py_ssize_t size) |
786 | | /*[clinic end generated code: output=42528d39dd0ca641 input=bec9a2c704ddcbc9]*/ |
787 | 0 | { |
788 | 0 | char *ptr; |
789 | 0 | Py_ssize_t n; |
790 | 0 | PyObject *bytes; |
791 | |
|
792 | 0 | if (self->fd < 0) |
793 | 0 | return err_closed(); |
794 | 0 | if (!self->readable) |
795 | 0 | return err_mode("reading"); |
796 | | |
797 | 0 | if (size < 0) |
798 | 0 | return _io_FileIO_readall_impl(self); |
799 | | |
800 | 0 | if (size > _PY_READ_MAX) { |
801 | 0 | size = _PY_READ_MAX; |
802 | 0 | } |
803 | |
|
804 | 0 | bytes = PyBytes_FromStringAndSize(NULL, size); |
805 | 0 | if (bytes == NULL) |
806 | 0 | return NULL; |
807 | 0 | ptr = PyBytes_AS_STRING(bytes); |
808 | |
|
809 | 0 | n = _Py_read(self->fd, ptr, size); |
810 | 0 | if (n == -1) { |
811 | | /* copy errno because Py_DECREF() can indirectly modify it */ |
812 | 0 | int err = errno; |
813 | 0 | Py_DECREF(bytes); |
814 | 0 | if (err == EAGAIN) { |
815 | 0 | PyErr_Clear(); |
816 | 0 | Py_RETURN_NONE; |
817 | 0 | } |
818 | 0 | return NULL; |
819 | 0 | } |
820 | | |
821 | 0 | if (n != size) { |
822 | 0 | if (_PyBytes_Resize(&bytes, n) < 0) { |
823 | 0 | Py_CLEAR(bytes); |
824 | 0 | return NULL; |
825 | 0 | } |
826 | 0 | } |
827 | | |
828 | 0 | return (PyObject *) bytes; |
829 | 0 | } |
830 | | |
831 | | /*[clinic input] |
832 | | _io.FileIO.write |
833 | | b: Py_buffer |
834 | | / |
835 | | |
836 | | Write buffer b to file, return number of bytes written. |
837 | | |
838 | | Only makes one system call, so not all of the data may be written. |
839 | | The number of bytes actually written is returned. In non-blocking mode, |
840 | | returns None if the write would block. |
841 | | [clinic start generated code]*/ |
842 | | |
843 | | static PyObject * |
844 | | _io_FileIO_write_impl(fileio *self, Py_buffer *b) |
845 | | /*[clinic end generated code: output=b4059db3d363a2f7 input=6e7908b36f0ce74f]*/ |
846 | 14 | { |
847 | 14 | Py_ssize_t n; |
848 | 14 | int err; |
849 | | |
850 | 14 | if (self->fd < 0) |
851 | 0 | return err_closed(); |
852 | 14 | if (!self->writable) |
853 | 0 | return err_mode("writing"); |
854 | | |
855 | 14 | n = _Py_write(self->fd, b->buf, b->len); |
856 | | /* copy errno because PyBuffer_Release() can indirectly modify it */ |
857 | 14 | err = errno; |
858 | | |
859 | 14 | if (n < 0) { |
860 | 0 | if (err == EAGAIN) { |
861 | 0 | PyErr_Clear(); |
862 | 0 | Py_RETURN_NONE; |
863 | 0 | } |
864 | 0 | return NULL; |
865 | 0 | } |
866 | | |
867 | 14 | return PyLong_FromSsize_t(n); |
868 | 14 | } |
869 | | |
870 | | /* XXX Windows support below is likely incomplete */ |
871 | | |
872 | | /* Cribbed from posix_lseek() */ |
873 | | static PyObject * |
874 | | portable_lseek(fileio *self, PyObject *posobj, int whence, bool suppress_pipe_error) |
875 | 306 | { |
876 | 306 | Py_off_t pos, res; |
877 | 306 | int fd = self->fd; |
878 | | |
879 | 306 | #ifdef SEEK_SET |
880 | | /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */ |
881 | 306 | switch (whence) { |
882 | | #if SEEK_SET != 0 |
883 | | case 0: whence = SEEK_SET; break; |
884 | | #endif |
885 | | #if SEEK_CUR != 1 |
886 | | case 1: whence = SEEK_CUR; break; |
887 | | #endif |
888 | | #if SEEK_END != 2 |
889 | | case 2: whence = SEEK_END; break; |
890 | | #endif |
891 | 306 | } |
892 | 306 | #endif /* SEEK_SET */ |
893 | | |
894 | 306 | if (posobj == NULL) { |
895 | 306 | pos = 0; |
896 | 306 | } |
897 | 0 | else { |
898 | 0 | if(PyFloat_Check(posobj)) { |
899 | 0 | PyErr_SetString(PyExc_TypeError, "an integer is required"); |
900 | 0 | return NULL; |
901 | 0 | } |
902 | | #if defined(HAVE_LARGEFILE_SUPPORT) |
903 | | pos = PyLong_AsLongLong(posobj); |
904 | | #else |
905 | 0 | pos = PyLong_AsLong(posobj); |
906 | 0 | #endif |
907 | 0 | if (PyErr_Occurred()) |
908 | 0 | return NULL; |
909 | 0 | } |
910 | | |
911 | 306 | Py_BEGIN_ALLOW_THREADS |
912 | 306 | _Py_BEGIN_SUPPRESS_IPH |
913 | | #ifdef MS_WINDOWS |
914 | | res = _lseeki64(fd, pos, whence); |
915 | | #else |
916 | 306 | res = lseek(fd, pos, whence); |
917 | 306 | #endif |
918 | 306 | _Py_END_SUPPRESS_IPH |
919 | 306 | Py_END_ALLOW_THREADS |
920 | | |
921 | 306 | if (self->seekable < 0) { |
922 | 278 | self->seekable = (res >= 0); |
923 | 278 | } |
924 | | |
925 | 306 | if (res < 0) { |
926 | 0 | if (suppress_pipe_error && errno == ESPIPE) { |
927 | 0 | res = 0; |
928 | 0 | } else { |
929 | 0 | return PyErr_SetFromErrno(PyExc_OSError); |
930 | 0 | } |
931 | 0 | } |
932 | | |
933 | | #if defined(HAVE_LARGEFILE_SUPPORT) |
934 | | return PyLong_FromLongLong(res); |
935 | | #else |
936 | 306 | return PyLong_FromLong(res); |
937 | 306 | #endif |
938 | 306 | } |
939 | | |
940 | | /*[clinic input] |
941 | | _io.FileIO.seek |
942 | | pos: object |
943 | | whence: int = 0 |
944 | | / |
945 | | |
946 | | Move to new file position and return the file position. |
947 | | |
948 | | Argument offset is a byte count. Optional argument whence defaults to |
949 | | SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values |
950 | | are SEEK_CUR or 1 (move relative to current position, positive or negative), |
951 | | and SEEK_END or 2 (move relative to end of file, usually negative, although |
952 | | many platforms allow seeking beyond the end of a file). |
953 | | |
954 | | Note that not all file objects are seekable. |
955 | | [clinic start generated code]*/ |
956 | | |
957 | | static PyObject * |
958 | | _io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence) |
959 | | /*[clinic end generated code: output=c976acdf054e6655 input=0439194b0774d454]*/ |
960 | 0 | { |
961 | 0 | if (self->fd < 0) |
962 | 0 | return err_closed(); |
963 | | |
964 | 0 | return portable_lseek(self, pos, whence, false); |
965 | 0 | } |
966 | | |
967 | | /*[clinic input] |
968 | | _io.FileIO.tell |
969 | | |
970 | | Current file position. |
971 | | |
972 | | Can raise OSError for non seekable files. |
973 | | [clinic start generated code]*/ |
974 | | |
975 | | static PyObject * |
976 | | _io_FileIO_tell_impl(fileio *self) |
977 | | /*[clinic end generated code: output=ffe2147058809d0b input=807e24ead4cec2f9]*/ |
978 | 306 | { |
979 | 306 | if (self->fd < 0) |
980 | 0 | return err_closed(); |
981 | | |
982 | 306 | return portable_lseek(self, NULL, 1, false); |
983 | 306 | } |
984 | | |
985 | | #ifdef HAVE_FTRUNCATE |
986 | | /*[clinic input] |
987 | | _io.FileIO.truncate |
988 | | size as posobj: object = None |
989 | | / |
990 | | |
991 | | Truncate the file to at most size bytes and return the truncated size. |
992 | | |
993 | | Size defaults to the current file position, as returned by tell(). |
994 | | The current file position is changed to the value of size. |
995 | | [clinic start generated code]*/ |
996 | | |
997 | | static PyObject * |
998 | | _io_FileIO_truncate_impl(fileio *self, PyObject *posobj) |
999 | | /*[clinic end generated code: output=e49ca7a916c176fa input=b0ac133939823875]*/ |
1000 | 0 | { |
1001 | 0 | Py_off_t pos; |
1002 | 0 | int ret; |
1003 | 0 | int fd; |
1004 | |
|
1005 | 0 | fd = self->fd; |
1006 | 0 | if (fd < 0) |
1007 | 0 | return err_closed(); |
1008 | 0 | if (!self->writable) |
1009 | 0 | return err_mode("writing"); |
1010 | | |
1011 | 0 | if (posobj == Py_None) { |
1012 | | /* Get the current position. */ |
1013 | 0 | posobj = portable_lseek(self, NULL, 1, false); |
1014 | 0 | if (posobj == NULL) |
1015 | 0 | return NULL; |
1016 | 0 | } |
1017 | 0 | else { |
1018 | 0 | Py_INCREF(posobj); |
1019 | 0 | } |
1020 | | |
1021 | | #if defined(HAVE_LARGEFILE_SUPPORT) |
1022 | | pos = PyLong_AsLongLong(posobj); |
1023 | | #else |
1024 | 0 | pos = PyLong_AsLong(posobj); |
1025 | 0 | #endif |
1026 | 0 | if (PyErr_Occurred()){ |
1027 | 0 | Py_DECREF(posobj); |
1028 | 0 | return NULL; |
1029 | 0 | } |
1030 | | |
1031 | 0 | Py_BEGIN_ALLOW_THREADS |
1032 | 0 | _Py_BEGIN_SUPPRESS_IPH |
1033 | 0 | errno = 0; |
1034 | | #ifdef MS_WINDOWS |
1035 | | ret = _chsize_s(fd, pos); |
1036 | | #else |
1037 | 0 | ret = ftruncate(fd, pos); |
1038 | 0 | #endif |
1039 | 0 | _Py_END_SUPPRESS_IPH |
1040 | 0 | Py_END_ALLOW_THREADS |
1041 | |
|
1042 | 0 | if (ret != 0) { |
1043 | 0 | Py_DECREF(posobj); |
1044 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
1045 | 0 | return NULL; |
1046 | 0 | } |
1047 | | |
1048 | 0 | return posobj; |
1049 | 0 | } |
1050 | | #endif /* HAVE_FTRUNCATE */ |
1051 | | |
1052 | | static const char * |
1053 | | mode_string(fileio *self) |
1054 | 0 | { |
1055 | 0 | if (self->created) { |
1056 | 0 | if (self->readable) |
1057 | 0 | return "xb+"; |
1058 | 0 | else |
1059 | 0 | return "xb"; |
1060 | 0 | } |
1061 | 0 | if (self->appending) { |
1062 | 0 | if (self->readable) |
1063 | 0 | return "ab+"; |
1064 | 0 | else |
1065 | 0 | return "ab"; |
1066 | 0 | } |
1067 | 0 | else if (self->readable) { |
1068 | 0 | if (self->writable) |
1069 | 0 | return "rb+"; |
1070 | 0 | else |
1071 | 0 | return "rb"; |
1072 | 0 | } |
1073 | 0 | else |
1074 | 0 | return "wb"; |
1075 | 0 | } |
1076 | | |
1077 | | static PyObject * |
1078 | | fileio_repr(fileio *self) |
1079 | 0 | { |
1080 | 0 | PyObject *nameobj, *res; |
1081 | |
|
1082 | 0 | if (self->fd < 0) |
1083 | 0 | return PyUnicode_FromFormat("<_io.FileIO [closed]>"); |
1084 | | |
1085 | 0 | if (_PyObject_LookupAttrId((PyObject *) self, &PyId_name, &nameobj) < 0) { |
1086 | 0 | return NULL; |
1087 | 0 | } |
1088 | 0 | if (nameobj == NULL) { |
1089 | 0 | res = PyUnicode_FromFormat( |
1090 | 0 | "<_io.FileIO fd=%d mode='%s' closefd=%s>", |
1091 | 0 | self->fd, mode_string(self), self->closefd ? "True" : "False"); |
1092 | 0 | } |
1093 | 0 | else { |
1094 | 0 | int status = Py_ReprEnter((PyObject *)self); |
1095 | 0 | res = NULL; |
1096 | 0 | if (status == 0) { |
1097 | 0 | res = PyUnicode_FromFormat( |
1098 | 0 | "<_io.FileIO name=%R mode='%s' closefd=%s>", |
1099 | 0 | nameobj, mode_string(self), self->closefd ? "True" : "False"); |
1100 | 0 | Py_ReprLeave((PyObject *)self); |
1101 | 0 | } |
1102 | 0 | else if (status > 0) { |
1103 | 0 | PyErr_Format(PyExc_RuntimeError, |
1104 | 0 | "reentrant call inside %s.__repr__", |
1105 | 0 | Py_TYPE(self)->tp_name); |
1106 | 0 | } |
1107 | 0 | Py_DECREF(nameobj); |
1108 | 0 | } |
1109 | 0 | return res; |
1110 | 0 | } |
1111 | | |
1112 | | /*[clinic input] |
1113 | | _io.FileIO.isatty |
1114 | | |
1115 | | True if the file is connected to a TTY device. |
1116 | | [clinic start generated code]*/ |
1117 | | |
1118 | | static PyObject * |
1119 | | _io_FileIO_isatty_impl(fileio *self) |
1120 | | /*[clinic end generated code: output=932c39924e9a8070 input=cd94ca1f5e95e843]*/ |
1121 | 320 | { |
1122 | 320 | long res; |
1123 | | |
1124 | 320 | if (self->fd < 0) |
1125 | 0 | return err_closed(); |
1126 | 320 | Py_BEGIN_ALLOW_THREADS |
1127 | 320 | _Py_BEGIN_SUPPRESS_IPH |
1128 | 320 | res = isatty(self->fd); |
1129 | 320 | _Py_END_SUPPRESS_IPH |
1130 | 320 | Py_END_ALLOW_THREADS |
1131 | 320 | return PyBool_FromLong(res); |
1132 | 320 | } |
1133 | | |
1134 | | #include "clinic/fileio.c.h" |
1135 | | |
1136 | | static PyMethodDef fileio_methods[] = { |
1137 | | _IO_FILEIO_READ_METHODDEF |
1138 | | _IO_FILEIO_READALL_METHODDEF |
1139 | | _IO_FILEIO_READINTO_METHODDEF |
1140 | | _IO_FILEIO_WRITE_METHODDEF |
1141 | | _IO_FILEIO_SEEK_METHODDEF |
1142 | | _IO_FILEIO_TELL_METHODDEF |
1143 | | _IO_FILEIO_TRUNCATE_METHODDEF |
1144 | | _IO_FILEIO_CLOSE_METHODDEF |
1145 | | _IO_FILEIO_SEEKABLE_METHODDEF |
1146 | | _IO_FILEIO_READABLE_METHODDEF |
1147 | | _IO_FILEIO_WRITABLE_METHODDEF |
1148 | | _IO_FILEIO_FILENO_METHODDEF |
1149 | | _IO_FILEIO_ISATTY_METHODDEF |
1150 | | {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL}, |
1151 | | {NULL, NULL} /* sentinel */ |
1152 | | }; |
1153 | | |
1154 | | /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */ |
1155 | | |
1156 | | static PyObject * |
1157 | | get_closed(fileio *self, void *closure) |
1158 | 947 | { |
1159 | 947 | return PyBool_FromLong((long)(self->fd < 0)); |
1160 | 947 | } |
1161 | | |
1162 | | static PyObject * |
1163 | | get_closefd(fileio *self, void *closure) |
1164 | 0 | { |
1165 | 0 | return PyBool_FromLong((long)(self->closefd)); |
1166 | 0 | } |
1167 | | |
1168 | | static PyObject * |
1169 | | get_mode(fileio *self, void *closure) |
1170 | 0 | { |
1171 | 0 | return PyUnicode_FromString(mode_string(self)); |
1172 | 0 | } |
1173 | | |
1174 | | static PyGetSetDef fileio_getsetlist[] = { |
1175 | | {"closed", (getter)get_closed, NULL, "True if the file is closed"}, |
1176 | | {"closefd", (getter)get_closefd, NULL, |
1177 | | "True if the file descriptor will be closed by close()."}, |
1178 | | {"mode", (getter)get_mode, NULL, "String giving the file mode"}, |
1179 | | {NULL}, |
1180 | | }; |
1181 | | |
1182 | | static PyMemberDef fileio_members[] = { |
1183 | | {"_blksize", T_UINT, offsetof(fileio, blksize), 0}, |
1184 | | {"_finalizing", T_BOOL, offsetof(fileio, finalizing), 0}, |
1185 | | {NULL} |
1186 | | }; |
1187 | | |
1188 | | PyTypeObject PyFileIO_Type = { |
1189 | | PyVarObject_HEAD_INIT(NULL, 0) |
1190 | | "_io.FileIO", |
1191 | | sizeof(fileio), |
1192 | | 0, |
1193 | | (destructor)fileio_dealloc, /* tp_dealloc */ |
1194 | | 0, /* tp_vectorcall_offset */ |
1195 | | 0, /* tp_getattr */ |
1196 | | 0, /* tp_setattr */ |
1197 | | 0, /* tp_as_async */ |
1198 | | (reprfunc)fileio_repr, /* tp_repr */ |
1199 | | 0, /* tp_as_number */ |
1200 | | 0, /* tp_as_sequence */ |
1201 | | 0, /* tp_as_mapping */ |
1202 | | 0, /* tp_hash */ |
1203 | | 0, /* tp_call */ |
1204 | | 0, /* tp_str */ |
1205 | | PyObject_GenericGetAttr, /* tp_getattro */ |
1206 | | 0, /* tp_setattro */ |
1207 | | 0, /* tp_as_buffer */ |
1208 | | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
1209 | | | Py_TPFLAGS_HAVE_GC, /* tp_flags */ |
1210 | | _io_FileIO___init____doc__, /* tp_doc */ |
1211 | | (traverseproc)fileio_traverse, /* tp_traverse */ |
1212 | | (inquiry)fileio_clear, /* tp_clear */ |
1213 | | 0, /* tp_richcompare */ |
1214 | | offsetof(fileio, weakreflist), /* tp_weaklistoffset */ |
1215 | | 0, /* tp_iter */ |
1216 | | 0, /* tp_iternext */ |
1217 | | fileio_methods, /* tp_methods */ |
1218 | | fileio_members, /* tp_members */ |
1219 | | fileio_getsetlist, /* tp_getset */ |
1220 | | 0, /* tp_base */ |
1221 | | 0, /* tp_dict */ |
1222 | | 0, /* tp_descr_get */ |
1223 | | 0, /* tp_descr_set */ |
1224 | | offsetof(fileio, dict), /* tp_dictoffset */ |
1225 | | _io_FileIO___init__, /* tp_init */ |
1226 | | PyType_GenericAlloc, /* tp_alloc */ |
1227 | | fileio_new, /* tp_new */ |
1228 | | PyObject_GC_Del, /* tp_free */ |
1229 | | 0, /* tp_is_gc */ |
1230 | | 0, /* tp_bases */ |
1231 | | 0, /* tp_mro */ |
1232 | | 0, /* tp_cache */ |
1233 | | 0, /* tp_subclasses */ |
1234 | | 0, /* tp_weaklist */ |
1235 | | 0, /* tp_del */ |
1236 | | 0, /* tp_version_tag */ |
1237 | | 0, /* tp_finalize */ |
1238 | | }; |