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