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