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