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