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