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