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