1 /* Author: Daniel Stutzbach */
3 #define PY_SSIZE_T_CLEAN
5 #ifdef HAVE_SYS_TYPES_H
14 #include <stddef.h> /* For offsetof */
15 #include "_iomodule.h"
18 * Known likely problems:
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
27 * - autoconfify header file inclusion
31 /* can simulate truncate with Win32 API functions; see file_truncate */
32 #define HAVE_FTRUNCATE
33 #define WIN32_LEAN_AND_MEAN
38 #define SMALLCHUNK (8*1024)
39 #elif (BUFSIZ >= (2 << 25))
40 #error "unreasonable BUFSIZ > 64MB defined"
42 #define SMALLCHUNK BUFSIZ
46 #define BIGCHUNK (512 * 32)
48 #define BIGCHUNK (512 * 1024)
54 unsigned int readable
: 1;
55 unsigned int writable
: 1;
56 signed int seekable
: 2; /* -1 means unknown */
57 unsigned int closefd
: 1;
58 PyObject
*weakreflist
;
62 PyTypeObject PyFileIO_Type
;
64 #define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
67 _PyFileIO_closed(PyObject
*self
)
69 return ((fileio
*)self
)->fd
< 0;
73 portable_lseek(int fd
, PyObject
*posobj
, int whence
);
75 static PyObject
*portable_lseek(int fd
, PyObject
*posobj
, int whence
);
77 /* Returns 0 on success, -1 with exception set on failure. */
79 internal_close(fileio
*self
)
86 /* fd is accessible and someone else may have closed it */
87 if (_PyVerify_fd(fd
)) {
88 Py_BEGIN_ALLOW_THREADS
100 PyErr_SetFromErrno(PyExc_IOError
);
107 fileio_close(fileio
*self
)
109 if (!self
->closefd
) {
113 errno
= internal_close(self
);
117 return PyObject_CallMethod((PyObject
*)&PyRawIOBase_Type
,
122 fileio_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
126 assert(type
!= NULL
&& type
->tp_alloc
!= NULL
);
128 self
= (fileio
*) type
->tp_alloc(type
, 0);
135 self
->weakreflist
= NULL
;
138 return (PyObject
*) self
;
141 /* On Unix, open will succeed for directories.
142 In Python, there should be no file objects referring to
143 directories, so we need a check. */
146 dircheck(fileio
* self
, const char *name
)
148 #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
152 if (fstat(self
->fd
, &buf
) == 0 && S_ISDIR(buf
.st_mode
)) {
153 char *msg
= strerror(EISDIR
);
155 if (internal_close(self
))
158 exc
= PyObject_CallFunction(PyExc_IOError
, "(iss)",
160 PyErr_SetObject(PyExc_IOError
, exc
);
171 #if defined(HAVE_FSTAT)
173 if (!_PyVerify_fd(fd
) || (fstat(fd
, &buf
) < 0 && errno
== EBADF
)) {
175 char *msg
= strerror(EBADF
);
176 exc
= PyObject_CallFunction(PyExc_OSError
, "(is)",
178 PyErr_SetObject(PyExc_OSError
, exc
);
188 fileio_init(PyObject
*oself
, PyObject
*args
, PyObject
*kwds
)
190 fileio
*self
= (fileio
*) oself
;
191 static char *kwlist
[] = {"file", "mode", "closefd", NULL
};
192 const char *name
= NULL
;
193 PyObject
*nameobj
, *stringobj
= NULL
;
197 Py_UNICODE
*widename
= NULL
;
200 int rwa
= 0, plus
= 0, append
= 0;
205 assert(PyFileIO_Check(oself
));
207 /* Have to close the existing file first. */
208 if (internal_close(self
) < 0)
212 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "O|si:fileio",
213 kwlist
, &nameobj
, &mode
, &closefd
))
216 if (PyFloat_Check(nameobj
)) {
217 PyErr_SetString(PyExc_TypeError
,
218 "integer argument expected, got float");
222 fd
= PyLong_AsLong(nameobj
);
224 if (!PyErr_Occurred()) {
225 PyErr_SetString(PyExc_ValueError
,
226 "Negative filedescriptor");
233 if (PyUnicode_Check(nameobj
))
234 widename
= PyUnicode_AS_UNICODE(nameobj
);
235 if (widename
== NULL
)
239 if (PyBytes_Check(nameobj
) || PyByteArray_Check(nameobj
)) {
241 if (PyObject_AsCharBuffer(nameobj
, &name
, &namelen
) < 0)
245 PyObject
*u
= PyUnicode_FromObject(nameobj
);
250 stringobj
= PyUnicode_AsEncodedString(
251 u
, Py_FileSystemDefaultEncoding
, NULL
);
253 if (stringobj
== NULL
)
255 if (!PyBytes_Check(stringobj
)) {
256 PyErr_SetString(PyExc_TypeError
,
257 "encoder failed to return bytes");
260 name
= PyBytes_AS_STRING(stringobj
);
270 PyErr_SetString(PyExc_ValueError
,
271 "Must have exactly one of read/write/append "
272 "mode and at most one plus");
283 flags
|= O_CREAT
| O_TRUNC
;
298 self
->readable
= self
->writable
= 1;
302 PyErr_Format(PyExc_ValueError
,
303 "invalid mode: %.200s", mode
);
311 if (self
->readable
&& self
->writable
)
313 else if (self
->readable
)
331 self
->closefd
= closefd
;
336 PyErr_SetString(PyExc_ValueError
,
337 "Cannot use closefd=False with file name");
341 Py_BEGIN_ALLOW_THREADS
344 if (widename
!= NULL
)
345 self
->fd
= _wopen(widename
, flags
, 0666);
348 self
->fd
= open(name
, flags
, 0666);
352 if (widename
!= NULL
)
353 PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError
, widename
);
356 PyErr_SetFromErrnoWithFilename(PyExc_IOError
, name
);
359 if(dircheck(self
, name
) < 0)
363 if (PyObject_SetAttrString((PyObject
*)self
, "name", nameobj
) < 0)
367 /* For consistent behaviour, we explicitly seek to the
368 end of file (otherwise, it might be done only on the
370 PyObject
*pos
= portable_lseek(self
->fd
, NULL
, 2);
392 fileio_traverse(fileio
*self
, visitproc visit
, void *arg
)
394 Py_VISIT(self
->dict
);
399 fileio_clear(fileio
*self
)
401 Py_CLEAR(self
->dict
);
406 fileio_dealloc(fileio
*self
)
408 if (_PyIOBase_finalize((PyObject
*) self
) < 0)
410 _PyObject_GC_UNTRACK(self
);
411 if (self
->weakreflist
!= NULL
)
412 PyObject_ClearWeakRefs((PyObject
*) self
);
413 Py_CLEAR(self
->dict
);
414 Py_TYPE(self
)->tp_free((PyObject
*)self
);
420 PyErr_SetString(PyExc_ValueError
, "I/O operation on closed file");
425 err_mode(char *action
)
427 PyErr_Format(PyExc_ValueError
, "File not open for %s", action
);
432 fileio_fileno(fileio
*self
)
436 return PyInt_FromLong((long) self
->fd
);
440 fileio_readable(fileio
*self
)
444 return PyBool_FromLong((long) self
->readable
);
448 fileio_writable(fileio
*self
)
452 return PyBool_FromLong((long) self
->writable
);
456 fileio_seekable(fileio
*self
)
460 if (self
->seekable
< 0) {
461 PyObject
*pos
= portable_lseek(self
->fd
, NULL
, SEEK_CUR
);
470 return PyBool_FromLong((long) self
->seekable
);
474 fileio_readinto(fileio
*self
, PyObject
*args
)
482 return err_mode("reading");
484 if (!PyArg_ParseTuple(args
, "w*", &pbuf
))
487 if (_PyVerify_fd(self
->fd
)) {
488 Py_BEGIN_ALLOW_THREADS
490 n
= read(self
->fd
, pbuf
.buf
, pbuf
.len
);
494 PyBuffer_Release(&pbuf
);
498 PyErr_SetFromErrno(PyExc_IOError
);
502 return PyLong_FromSsize_t(n
);
506 new_buffersize(fileio
*self
, size_t currentsize
)
511 if (fstat(self
->fd
, &st
) == 0) {
513 pos
= lseek(self
->fd
, 0L, SEEK_CUR
);
514 /* Files claiming a size smaller than SMALLCHUNK may
515 actually be streaming pseudo-files. In this case, we
516 apply the more aggressive algorithm below.
518 if (end
>= SMALLCHUNK
&& end
>= pos
&& pos
>= 0) {
519 /* Add 1 so if the file were to grow we'd notice. */
520 return currentsize
+ end
- pos
+ 1;
524 if (currentsize
> SMALLCHUNK
) {
525 /* Keep doubling until we reach BIGCHUNK;
526 then keep adding BIGCHUNK. */
527 if (currentsize
<= BIGCHUNK
)
528 return currentsize
+ currentsize
;
530 return currentsize
+ BIGCHUNK
;
532 return currentsize
+ SMALLCHUNK
;
536 fileio_readall(fileio
*self
)
539 Py_ssize_t total
= 0;
544 if (!_PyVerify_fd(self
->fd
))
545 return PyErr_SetFromErrno(PyExc_IOError
);
547 result
= PyBytes_FromStringAndSize(NULL
, SMALLCHUNK
);
552 size_t newsize
= new_buffersize(self
, total
);
553 if (newsize
> PY_SSIZE_T_MAX
|| newsize
<= 0) {
554 PyErr_SetString(PyExc_OverflowError
,
555 "unbounded read returned more bytes "
556 "than a Python string can hold ");
561 if (PyBytes_GET_SIZE(result
) < (Py_ssize_t
)newsize
) {
562 if (_PyBytes_Resize(&result
, newsize
) < 0) {
571 Py_BEGIN_ALLOW_THREADS
574 PyBytes_AS_STRING(result
) + total
,
582 if (errno
== EAGAIN
) {
587 PyErr_SetFromErrno(PyExc_IOError
);
593 if (PyBytes_GET_SIZE(result
) > total
) {
594 if (_PyBytes_Resize(&result
, total
) < 0) {
595 /* This should never happen, but just in case */
604 fileio_read(fileio
*self
, PyObject
*args
)
608 Py_ssize_t size
= -1;
614 return err_mode("reading");
616 if (!PyArg_ParseTuple(args
, "|O&", &_PyIO_ConvertSsize_t
, &size
))
620 return fileio_readall(self
);
623 bytes
= PyBytes_FromStringAndSize(NULL
, size
);
626 ptr
= PyBytes_AS_STRING(bytes
);
628 if (_PyVerify_fd(self
->fd
)) {
629 Py_BEGIN_ALLOW_THREADS
631 n
= read(self
->fd
, ptr
, size
);
640 PyErr_SetFromErrno(PyExc_IOError
);
645 if (_PyBytes_Resize(&bytes
, n
) < 0) {
651 return (PyObject
*) bytes
;
655 fileio_write(fileio
*self
, PyObject
*args
)
663 return err_mode("writing");
665 if (!PyArg_ParseTuple(args
, "s*", &pbuf
))
668 if (_PyVerify_fd(self
->fd
)) {
669 Py_BEGIN_ALLOW_THREADS
671 n
= write(self
->fd
, pbuf
.buf
, pbuf
.len
);
676 PyBuffer_Release(&pbuf
);
681 PyErr_SetFromErrno(PyExc_IOError
);
685 return PyLong_FromSsize_t(n
);
688 /* XXX Windows support below is likely incomplete */
690 /* Cribbed from posix_lseek() */
692 portable_lseek(int fd
, PyObject
*posobj
, int whence
)
697 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
700 case 0: whence
= SEEK_SET
; break;
703 case 1: whence
= SEEK_CUR
; break;
706 case 2: whence
= SEEK_END
; break;
709 #endif /* SEEK_SET */
714 if(PyFloat_Check(posobj
)) {
715 PyErr_SetString(PyExc_TypeError
, "an integer is required");
718 #if defined(HAVE_LARGEFILE_SUPPORT)
719 pos
= PyLong_AsLongLong(posobj
);
721 pos
= PyLong_AsLong(posobj
);
723 if (PyErr_Occurred())
727 if (_PyVerify_fd(fd
)) {
728 Py_BEGIN_ALLOW_THREADS
729 #if defined(MS_WIN64) || defined(MS_WINDOWS)
730 res
= _lseeki64(fd
, pos
, whence
);
732 res
= lseek(fd
, pos
, whence
);
738 return PyErr_SetFromErrno(PyExc_IOError
);
740 #if defined(HAVE_LARGEFILE_SUPPORT)
741 return PyLong_FromLongLong(res
);
743 return PyLong_FromLong(res
);
748 fileio_seek(fileio
*self
, PyObject
*args
)
756 if (!PyArg_ParseTuple(args
, "O|i", &posobj
, &whence
))
759 return portable_lseek(self
->fd
, posobj
, whence
);
763 fileio_tell(fileio
*self
, PyObject
*args
)
768 return portable_lseek(self
->fd
, NULL
, 1);
771 #ifdef HAVE_FTRUNCATE
773 fileio_truncate(fileio
*self
, PyObject
*args
)
775 PyObject
*posobj
= NULL
; /* the new size wanted by the user */
786 return err_mode("writing");
788 if (!PyArg_ParseTuple(args
, "|O", &posobj
))
791 if (posobj
== Py_None
|| posobj
== NULL
) {
792 /* Get the current position. */
793 posobj
= portable_lseek(fd
, NULL
, 1);
802 /* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
803 so don't even try using it. */
805 PyObject
*oldposobj
, *tempposobj
;
808 /* we save the file pointer position */
809 oldposobj
= portable_lseek(fd
, NULL
, 1);
810 if (oldposobj
== NULL
) {
815 /* we then move to the truncation position */
816 tempposobj
= portable_lseek(fd
, posobj
, 0);
817 if (tempposobj
== NULL
) {
818 Py_DECREF(oldposobj
);
822 Py_DECREF(tempposobj
);
824 /* Truncate. Note that this may grow the file! */
825 Py_BEGIN_ALLOW_THREADS
827 hFile
= (HANDLE
)_get_osfhandle(fd
);
828 ret
= hFile
== (HANDLE
)-1; /* testing for INVALID_HANDLE value */
830 ret
= SetEndOfFile(hFile
) == 0;
836 /* we restore the file pointer position in any case */
837 tempposobj
= portable_lseek(fd
, oldposobj
, 0);
838 Py_DECREF(oldposobj
);
839 if (tempposobj
== NULL
) {
843 Py_DECREF(tempposobj
);
847 #if defined(HAVE_LARGEFILE_SUPPORT)
848 pos
= PyLong_AsLongLong(posobj
);
850 pos
= PyLong_AsLong(posobj
);
852 if (PyErr_Occurred()){
857 Py_BEGIN_ALLOW_THREADS
859 ret
= ftruncate(fd
, pos
);
862 #endif /* !MS_WINDOWS */
866 PyErr_SetFromErrno(PyExc_IOError
);
872 #endif /* HAVE_FTRUNCATE */
875 mode_string(fileio
*self
)
877 if (self
->readable
) {
888 fileio_repr(fileio
*self
)
890 PyObject
*nameobj
, *res
;
893 return PyString_FromFormat("<_io.FileIO [closed]>");
895 nameobj
= PyObject_GetAttrString((PyObject
*) self
, "name");
896 if (nameobj
== NULL
) {
897 if (PyErr_ExceptionMatches(PyExc_AttributeError
))
901 res
= PyString_FromFormat("<_io.FileIO fd=%d mode='%s'>",
902 self
->fd
, mode_string(self
));
905 PyObject
*repr
= PyObject_Repr(nameobj
);
909 res
= PyString_FromFormat("<_io.FileIO name=%s mode='%s'>",
910 PyString_AS_STRING(repr
),
918 fileio_isatty(fileio
*self
)
924 Py_BEGIN_ALLOW_THREADS
925 res
= isatty(self
->fd
);
927 return PyBool_FromLong(res
);
931 PyDoc_STRVAR(fileio_doc
,
932 "file(name: str[, mode: str]) -> file IO object\n"
934 "Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n"
935 "writing or appending. The file will be created if it doesn't exist\n"
936 "when opened for writing or appending; it will be truncated when\n"
937 "opened for writing. Add a '+' to the mode to allow simultaneous\n"
938 "reading and writing.");
940 PyDoc_STRVAR(read_doc
,
941 "read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"
943 "Only makes one system call, so less data may be returned than requested\n"
944 "In non-blocking mode, returns None if no data is available.\n"
945 "On end-of-file, returns ''.");
947 PyDoc_STRVAR(readall_doc
,
948 "readall() -> bytes. read all data from the file, returned as bytes.\n"
950 "In non-blocking mode, returns as much as is immediately available,\n"
951 "or None if no data is available. On end-of-file, returns ''.");
953 PyDoc_STRVAR(write_doc
,
954 "write(b: bytes) -> int. Write bytes b to file, return number written.\n"
956 "Only makes one system call, so not all of the data may be written.\n"
957 "The number of bytes actually written is returned.");
959 PyDoc_STRVAR(fileno_doc
,
960 "fileno() -> int. \"file descriptor\".\n"
962 "This is needed for lower-level file interfaces, such the fcntl module.");
964 PyDoc_STRVAR(seek_doc
,
965 "seek(offset: int[, whence: int]) -> None. Move to new file position.\n"
967 "Argument offset is a byte count. Optional argument whence defaults to\n"
968 "0 (offset from start of file, offset should be >= 0); other values are 1\n"
969 "(move relative to current position, positive or negative), and 2 (move\n"
970 "relative to end of file, usually negative, although many platforms allow\n"
971 "seeking beyond the end of a file)."
973 "Note that not all file objects are seekable.");
975 #ifdef HAVE_FTRUNCATE
976 PyDoc_STRVAR(truncate_doc
,
977 "truncate([size: int]) -> None. Truncate the file to at most size bytes.\n"
979 "Size defaults to the current file position, as returned by tell()."
980 "The current file position is changed to the value of size.");
983 PyDoc_STRVAR(tell_doc
,
984 "tell() -> int. Current file position");
986 PyDoc_STRVAR(readinto_doc
,
987 "readinto() -> Same as RawIOBase.readinto().");
989 PyDoc_STRVAR(close_doc
,
990 "close() -> None. Close the file.\n"
992 "A closed file cannot be used for further I/O operations. close() may be\n"
993 "called more than once without error. Changes the fileno to -1.");
995 PyDoc_STRVAR(isatty_doc
,
996 "isatty() -> bool. True if the file is connected to a tty device.");
998 PyDoc_STRVAR(seekable_doc
,
999 "seekable() -> bool. True if file supports random-access.");
1001 PyDoc_STRVAR(readable_doc
,
1002 "readable() -> bool. True if file was opened in a read mode.");
1004 PyDoc_STRVAR(writable_doc
,
1005 "writable() -> bool. True if file was opened in a write mode.");
1007 static PyMethodDef fileio_methods
[] = {
1008 {"read", (PyCFunction
)fileio_read
, METH_VARARGS
, read_doc
},
1009 {"readall", (PyCFunction
)fileio_readall
, METH_NOARGS
, readall_doc
},
1010 {"readinto", (PyCFunction
)fileio_readinto
, METH_VARARGS
, readinto_doc
},
1011 {"write", (PyCFunction
)fileio_write
, METH_VARARGS
, write_doc
},
1012 {"seek", (PyCFunction
)fileio_seek
, METH_VARARGS
, seek_doc
},
1013 {"tell", (PyCFunction
)fileio_tell
, METH_VARARGS
, tell_doc
},
1014 #ifdef HAVE_FTRUNCATE
1015 {"truncate", (PyCFunction
)fileio_truncate
, METH_VARARGS
, truncate_doc
},
1017 {"close", (PyCFunction
)fileio_close
, METH_NOARGS
, close_doc
},
1018 {"seekable", (PyCFunction
)fileio_seekable
, METH_NOARGS
, seekable_doc
},
1019 {"readable", (PyCFunction
)fileio_readable
, METH_NOARGS
, readable_doc
},
1020 {"writable", (PyCFunction
)fileio_writable
, METH_NOARGS
, writable_doc
},
1021 {"fileno", (PyCFunction
)fileio_fileno
, METH_NOARGS
, fileno_doc
},
1022 {"isatty", (PyCFunction
)fileio_isatty
, METH_NOARGS
, isatty_doc
},
1023 {NULL
, NULL
} /* sentinel */
1026 /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
1029 get_closed(fileio
*self
, void *closure
)
1031 return PyBool_FromLong((long)(self
->fd
< 0));
1035 get_closefd(fileio
*self
, void *closure
)
1037 return PyBool_FromLong((long)(self
->closefd
));
1041 get_mode(fileio
*self
, void *closure
)
1043 return PyUnicode_FromString(mode_string(self
));
1046 static PyGetSetDef fileio_getsetlist
[] = {
1047 {"closed", (getter
)get_closed
, NULL
, "True if the file is closed"},
1048 {"closefd", (getter
)get_closefd
, NULL
,
1049 "True if the file descriptor will be closed"},
1050 {"mode", (getter
)get_mode
, NULL
, "String giving the file mode"},
1054 PyTypeObject PyFileIO_Type
= {
1055 PyVarObject_HEAD_INIT(NULL
, 0)
1059 (destructor
)fileio_dealloc
, /* tp_dealloc */
1063 0, /* tp_reserved */
1064 (reprfunc
)fileio_repr
, /* tp_repr */
1065 0, /* tp_as_number */
1066 0, /* tp_as_sequence */
1067 0, /* tp_as_mapping */
1071 PyObject_GenericGetAttr
, /* tp_getattro */
1072 0, /* tp_setattro */
1073 0, /* tp_as_buffer */
1074 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
1075 | Py_TPFLAGS_HAVE_GC
, /* tp_flags */
1076 fileio_doc
, /* tp_doc */
1077 (traverseproc
)fileio_traverse
, /* tp_traverse */
1078 (inquiry
)fileio_clear
, /* tp_clear */
1079 0, /* tp_richcompare */
1080 offsetof(fileio
, weakreflist
), /* tp_weaklistoffset */
1082 0, /* tp_iternext */
1083 fileio_methods
, /* tp_methods */
1085 fileio_getsetlist
, /* tp_getset */
1088 0, /* tp_descr_get */
1089 0, /* tp_descr_set */
1090 offsetof(fileio
, dict
), /* tp_dictoffset */
1091 fileio_init
, /* tp_init */
1092 PyType_GenericAlloc
, /* tp_alloc */
1093 fileio_new
, /* tp_new */
1094 PyObject_GC_Del
, /* tp_free */