1 /* Author: Daniel Stutzbach */
3 #define PY_SSIZE_T_CLEAN
8 #include <stddef.h> /* For offsetof */
11 * Known likely problems:
13 * - Files larger then 2**32-1
14 * - Files with unicode filenames
15 * - Passing numbers greater than 2**32-1 when an integer is expected
16 * - Making it work on Windows and other oddball platforms
20 * - autoconfify header file inclusion
24 /* can simulate truncate with Win32 API functions; see file_truncate */
25 #define HAVE_FTRUNCATE
26 #define WIN32_LEAN_AND_MEAN
33 unsigned readable
: 1;
34 unsigned writable
: 1;
35 int seekable
: 2; /* -1 means unknown */
37 PyObject
*weakreflist
;
40 PyTypeObject PyFileIO_Type
;
42 #define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
44 /* Returns 0 on success, errno (which is < 0) on failure. */
46 internal_close(PyFileIOObject
*self
)
52 Py_BEGIN_ALLOW_THREADS
61 fileio_close(PyFileIOObject
*self
)
67 errno
= internal_close(self
);
69 PyErr_SetFromErrno(PyExc_IOError
);
77 fileio_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kews
)
81 assert(type
!= NULL
&& type
->tp_alloc
!= NULL
);
83 self
= (PyFileIOObject
*) type
->tp_alloc(type
, 0);
90 self
->weakreflist
= NULL
;
93 return (PyObject
*) self
;
96 /* On Unix, open will succeed for directories.
97 In Python, there should be no file objects referring to
98 directories, so we need a check. */
101 dircheck(PyFileIOObject
* self
, char *name
)
103 #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
107 if (fstat(self
->fd
, &buf
) == 0 && S_ISDIR(buf
.st_mode
)) {
108 char *msg
= strerror(EISDIR
);
110 internal_close(self
);
112 exc
= PyObject_CallFunction(PyExc_IOError
, "(iss)",
114 PyErr_SetObject(PyExc_IOError
, exc
);
124 fileio_init(PyObject
*oself
, PyObject
*args
, PyObject
*kwds
)
126 PyFileIOObject
*self
= (PyFileIOObject
*) oself
;
127 static char *kwlist
[] = {"file", "mode", "closefd", NULL
};
132 Py_UNICODE
*widename
= NULL
;
135 int rwa
= 0, plus
= 0, append
= 0;
140 assert(PyFileIO_Check(oself
));
142 /* Have to close the existing file first. */
143 if (internal_close(self
) < 0)
147 if (PyArg_ParseTupleAndKeywords(args
, kwds
, "i|si:fileio",
148 kwlist
, &fd
, &mode
, &closefd
)) {
150 PyErr_SetString(PyExc_ValueError
,
151 "Negative filedescriptor");
158 #ifdef Py_WIN_WIDE_FILENAMES
159 if (GetVersion() < 0x80000000) {
160 /* On NT, so wide API available */
162 if (PyArg_ParseTupleAndKeywords(args
, kwds
, "U|si:fileio",
163 kwlist
, &po
, &mode
, &closefd
)
165 widename
= PyUnicode_AS_UNICODE(po
);
167 /* Drop the argument parsing error as narrow
168 strings are also valid. */
172 if (widename
== NULL
)
175 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "et|si:fileio",
177 Py_FileSystemDefaultEncoding
,
178 &name
, &mode
, &closefd
))
189 PyErr_SetString(PyExc_ValueError
,
190 "Must have exactly one of read/write/append mode");
201 flags
|= O_CREAT
| O_TRUNC
;
216 self
->readable
= self
->writable
= 1;
220 PyErr_Format(PyExc_ValueError
,
221 "invalid mode: %.200s", mode
);
229 if (self
->readable
&& self
->writable
)
231 else if (self
->readable
)
247 self
->closefd
= closefd
;
252 PyErr_SetString(PyExc_ValueError
,
253 "Cannot use closefd=False with file name");
257 Py_BEGIN_ALLOW_THREADS
260 if (widename
!= NULL
)
261 self
->fd
= _wopen(widename
, flags
, 0666);
264 self
->fd
= open(name
, flags
, 0666);
268 if (widename
!= NULL
)
269 PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError
, widename
);
272 PyErr_SetFromErrnoWithFilename(PyExc_IOError
, name
);
275 if(dircheck(self
, name
) < 0)
290 fileio_dealloc(PyFileIOObject
*self
)
292 if (self
->weakreflist
!= NULL
)
293 PyObject_ClearWeakRefs((PyObject
*) self
);
295 if (self
->fd
>= 0 && self
->closefd
) {
296 errno
= internal_close(self
);
298 PySys_WriteStderr("close failed: [Errno %d] %s\n",
299 errno
, strerror(errno
));
303 Py_TYPE(self
)->tp_free((PyObject
*)self
);
309 PyErr_SetString(PyExc_ValueError
, "I/O operation on closed file");
314 err_mode(char *action
)
316 PyErr_Format(PyExc_ValueError
, "File not open for %s", action
);
321 fileio_fileno(PyFileIOObject
*self
)
325 return PyInt_FromLong((long) self
->fd
);
329 fileio_readable(PyFileIOObject
*self
)
333 return PyBool_FromLong((long) self
->readable
);
337 fileio_writable(PyFileIOObject
*self
)
341 return PyBool_FromLong((long) self
->writable
);
345 fileio_seekable(PyFileIOObject
*self
)
349 if (self
->seekable
< 0) {
351 Py_BEGIN_ALLOW_THREADS
352 ret
= lseek(self
->fd
, 0, SEEK_CUR
);
359 return PyBool_FromLong((long) self
->seekable
);
363 fileio_readinto(PyFileIOObject
*self
, PyObject
*args
)
371 return err_mode("reading");
373 if (!PyArg_ParseTuple(args
, "w*", &pbuf
))
376 Py_BEGIN_ALLOW_THREADS
378 n
= read(self
->fd
, pbuf
.buf
, pbuf
.len
);
380 PyBuffer_Release(&pbuf
);
384 PyErr_SetFromErrno(PyExc_IOError
);
388 return PyLong_FromSsize_t(n
);
391 #define DEFAULT_BUFFER_SIZE (8*1024)
394 fileio_readall(PyFileIOObject
*self
)
397 Py_ssize_t total
= 0;
400 result
= PyString_FromStringAndSize(NULL
, DEFAULT_BUFFER_SIZE
);
405 Py_ssize_t newsize
= total
+ DEFAULT_BUFFER_SIZE
;
406 if (PyString_GET_SIZE(result
) < newsize
) {
407 if (_PyString_Resize(&result
, newsize
) < 0) {
416 Py_BEGIN_ALLOW_THREADS
419 PyString_AS_STRING(result
) + total
,
427 if (errno
== EAGAIN
) {
432 PyErr_SetFromErrno(PyExc_IOError
);
438 if (PyString_GET_SIZE(result
) > total
) {
439 if (_PyString_Resize(&result
, total
) < 0) {
440 /* This should never happen, but just in case */
449 fileio_read(PyFileIOObject
*self
, PyObject
*args
)
453 Py_ssize_t size
= -1;
459 return err_mode("reading");
461 if (!PyArg_ParseTuple(args
, "|n", &size
))
465 return fileio_readall(self
);
468 bytes
= PyString_FromStringAndSize(NULL
, size
);
471 ptr
= PyString_AS_STRING(bytes
);
473 Py_BEGIN_ALLOW_THREADS
475 n
= read(self
->fd
, ptr
, size
);
481 PyErr_SetFromErrno(PyExc_IOError
);
486 if (_PyString_Resize(&bytes
, n
) < 0) {
492 return (PyObject
*) bytes
;
496 fileio_write(PyFileIOObject
*self
, PyObject
*args
)
504 return err_mode("writing");
506 if (!PyArg_ParseTuple(args
, "s*", &pbuf
))
509 Py_BEGIN_ALLOW_THREADS
511 n
= write(self
->fd
, pbuf
.buf
, pbuf
.len
);
514 PyBuffer_Release(&pbuf
);
519 PyErr_SetFromErrno(PyExc_IOError
);
523 return PyLong_FromSsize_t(n
);
526 /* XXX Windows support below is likely incomplete */
528 #if defined(MS_WIN64) || defined(MS_WINDOWS)
529 typedef PY_LONG_LONG Py_off_t
;
531 typedef off_t Py_off_t
;
534 /* Cribbed from posix_lseek() */
536 portable_lseek(int fd
, PyObject
*posobj
, int whence
)
541 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
544 case 0: whence
= SEEK_SET
; break;
547 case 1: whence
= SEEK_CUR
; break;
550 case 2: whence
= SEEK_END
; break;
553 #endif /* SEEK_SET */
558 if(PyFloat_Check(posobj
)) {
559 PyErr_SetString(PyExc_TypeError
, "an integer is required");
562 #if defined(HAVE_LARGEFILE_SUPPORT)
563 pos
= PyLong_AsLongLong(posobj
);
565 pos
= PyLong_AsLong(posobj
);
567 if (PyErr_Occurred())
571 Py_BEGIN_ALLOW_THREADS
572 #if defined(MS_WIN64) || defined(MS_WINDOWS)
573 res
= _lseeki64(fd
, pos
, whence
);
575 res
= lseek(fd
, pos
, whence
);
579 return PyErr_SetFromErrno(PyExc_IOError
);
581 #if defined(HAVE_LARGEFILE_SUPPORT)
582 return PyLong_FromLongLong(res
);
584 return PyLong_FromLong(res
);
589 fileio_seek(PyFileIOObject
*self
, PyObject
*args
)
597 if (!PyArg_ParseTuple(args
, "O|i", &posobj
, &whence
))
600 return portable_lseek(self
->fd
, posobj
, whence
);
604 fileio_tell(PyFileIOObject
*self
, PyObject
*args
)
609 return portable_lseek(self
->fd
, NULL
, 1);
612 #ifdef HAVE_FTRUNCATE
614 fileio_truncate(PyFileIOObject
*self
, PyObject
*args
)
616 PyObject
*posobj
= NULL
;
625 return err_mode("writing");
627 if (!PyArg_ParseTuple(args
, "|O", &posobj
))
630 if (posobj
== Py_None
|| posobj
== NULL
) {
631 /* Get the current position. */
632 posobj
= portable_lseek(fd
, NULL
, 1);
637 /* Move to the position to be truncated. */
638 posobj
= portable_lseek(fd
, posobj
, 0);
641 #if defined(HAVE_LARGEFILE_SUPPORT)
642 pos
= PyLong_AsLongLong(posobj
);
644 pos
= PyLong_AsLong(posobj
);
646 if (PyErr_Occurred())
650 /* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
651 so don't even try using it. */
655 /* Truncate. Note that this may grow the file! */
656 Py_BEGIN_ALLOW_THREADS
658 hFile
= (HANDLE
)_get_osfhandle(fd
);
659 ret
= hFile
== (HANDLE
)-1;
661 ret
= SetEndOfFile(hFile
) == 0;
668 Py_BEGIN_ALLOW_THREADS
670 ret
= ftruncate(fd
, pos
);
672 #endif /* !MS_WINDOWS */
675 PyErr_SetFromErrno(PyExc_IOError
);
684 mode_string(PyFileIOObject
*self
)
686 if (self
->readable
) {
697 fileio_repr(PyFileIOObject
*self
)
700 return PyString_FromFormat("_fileio._FileIO(-1)");
702 return PyString_FromFormat("_fileio._FileIO(%d, '%s')",
703 self
->fd
, mode_string(self
));
707 fileio_isatty(PyFileIOObject
*self
)
713 Py_BEGIN_ALLOW_THREADS
714 res
= isatty(self
->fd
);
716 return PyBool_FromLong(res
);
720 PyDoc_STRVAR(fileio_doc
,
721 "file(name: str[, mode: str]) -> file IO object\n"
723 "Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n"
724 "writing or appending. The file will be created if it doesn't exist\n"
725 "when opened for writing or appending; it will be truncated when\n"
726 "opened for writing. Add a '+' to the mode to allow simultaneous\n"
727 "reading and writing.");
729 PyDoc_STRVAR(read_doc
,
730 "read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"
732 "Only makes one system call, so less data may be returned than requested\n"
733 "In non-blocking mode, returns None if no data is available.\n"
734 "On end-of-file, returns ''.");
736 PyDoc_STRVAR(readall_doc
,
737 "readall() -> bytes. read all data from the file, returned as bytes.\n"
739 "In non-blocking mode, returns as much as is immediately available,\n"
740 "or None if no data is available. On end-of-file, returns ''.");
742 PyDoc_STRVAR(write_doc
,
743 "write(b: bytes) -> int. Write bytes b to file, return number written.\n"
745 "Only makes one system call, so not all of the data may be written.\n"
746 "The number of bytes actually written is returned.");
748 PyDoc_STRVAR(fileno_doc
,
749 "fileno() -> int. \"file descriptor\".\n"
751 "This is needed for lower-level file interfaces, such the fcntl module.");
753 PyDoc_STRVAR(seek_doc
,
754 "seek(offset: int[, whence: int]) -> None. Move to new file position.\n"
756 "Argument offset is a byte count. Optional argument whence defaults to\n"
757 "0 (offset from start of file, offset should be >= 0); other values are 1\n"
758 "(move relative to current position, positive or negative), and 2 (move\n"
759 "relative to end of file, usually negative, although many platforms allow\n"
760 "seeking beyond the end of a file)."
762 "Note that not all file objects are seekable.");
764 #ifdef HAVE_FTRUNCATE
765 PyDoc_STRVAR(truncate_doc
,
766 "truncate([size: int]) -> None. Truncate the file to at most size bytes.\n"
768 "Size defaults to the current file position, as returned by tell()."
769 "The current file position is changed to the value of size.");
772 PyDoc_STRVAR(tell_doc
,
773 "tell() -> int. Current file position");
775 PyDoc_STRVAR(readinto_doc
,
776 "readinto() -> Undocumented. Don't use this; it may go away.");
778 PyDoc_STRVAR(close_doc
,
779 "close() -> None. Close the file.\n"
781 "A closed file cannot be used for further I/O operations. close() may be\n"
782 "called more than once without error. Changes the fileno to -1.");
784 PyDoc_STRVAR(isatty_doc
,
785 "isatty() -> bool. True if the file is connected to a tty device.");
787 PyDoc_STRVAR(seekable_doc
,
788 "seekable() -> bool. True if file supports random-access.");
790 PyDoc_STRVAR(readable_doc
,
791 "readable() -> bool. True if file was opened in a read mode.");
793 PyDoc_STRVAR(writable_doc
,
794 "writable() -> bool. True if file was opened in a write mode.");
796 static PyMethodDef fileio_methods
[] = {
797 {"read", (PyCFunction
)fileio_read
, METH_VARARGS
, read_doc
},
798 {"readall", (PyCFunction
)fileio_readall
, METH_NOARGS
, readall_doc
},
799 {"readinto", (PyCFunction
)fileio_readinto
, METH_VARARGS
, readinto_doc
},
800 {"write", (PyCFunction
)fileio_write
, METH_VARARGS
, write_doc
},
801 {"seek", (PyCFunction
)fileio_seek
, METH_VARARGS
, seek_doc
},
802 {"tell", (PyCFunction
)fileio_tell
, METH_VARARGS
, tell_doc
},
803 #ifdef HAVE_FTRUNCATE
804 {"truncate", (PyCFunction
)fileio_truncate
, METH_VARARGS
, truncate_doc
},
806 {"close", (PyCFunction
)fileio_close
, METH_NOARGS
, close_doc
},
807 {"seekable", (PyCFunction
)fileio_seekable
, METH_NOARGS
, seekable_doc
},
808 {"readable", (PyCFunction
)fileio_readable
, METH_NOARGS
, readable_doc
},
809 {"writable", (PyCFunction
)fileio_writable
, METH_NOARGS
, writable_doc
},
810 {"fileno", (PyCFunction
)fileio_fileno
, METH_NOARGS
, fileno_doc
},
811 {"isatty", (PyCFunction
)fileio_isatty
, METH_NOARGS
, isatty_doc
},
812 {NULL
, NULL
} /* sentinel */
815 /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
818 get_closed(PyFileIOObject
*self
, void *closure
)
820 return PyBool_FromLong((long)(self
->fd
< 0));
824 get_closefd(PyFileIOObject
*self
, void *closure
)
826 return PyBool_FromLong((long)(self
->closefd
));
830 get_mode(PyFileIOObject
*self
, void *closure
)
832 return PyString_FromString(mode_string(self
));
835 static PyGetSetDef fileio_getsetlist
[] = {
836 {"closed", (getter
)get_closed
, NULL
, "True if the file is closed"},
837 {"closefd", (getter
)get_closefd
, NULL
,
838 "True if the file descriptor will be closed"},
839 {"mode", (getter
)get_mode
, NULL
, "String giving the file mode"},
843 PyTypeObject PyFileIO_Type
= {
844 PyVarObject_HEAD_INIT(NULL
, 0)
846 sizeof(PyFileIOObject
),
848 (destructor
)fileio_dealloc
, /* tp_dealloc */
853 (reprfunc
)fileio_repr
, /* tp_repr */
854 0, /* tp_as_number */
855 0, /* tp_as_sequence */
856 0, /* tp_as_mapping */
860 PyObject_GenericGetAttr
, /* tp_getattro */
862 0, /* tp_as_buffer */
863 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
864 fileio_doc
, /* tp_doc */
867 0, /* tp_richcompare */
868 offsetof(PyFileIOObject
, weakreflist
), /* tp_weaklistoffset */
871 fileio_methods
, /* tp_methods */
873 fileio_getsetlist
, /* tp_getset */
876 0, /* tp_descr_get */
877 0, /* tp_descr_set */
878 0, /* tp_dictoffset */
879 fileio_init
, /* tp_init */
880 PyType_GenericAlloc
, /* tp_alloc */
881 fileio_new
, /* tp_new */
882 PyObject_Del
, /* tp_free */
885 static PyMethodDef module_methods
[] = {
892 PyObject
*m
; /* a module object */
894 m
= Py_InitModule3("_fileio", module_methods
,
895 "Fast implementation of io.FileIO.");
898 if (PyType_Ready(&PyFileIO_Type
) < 0)
900 Py_INCREF(&PyFileIO_Type
);
901 PyModule_AddObject(m
, "_FileIO", (PyObject
*) &PyFileIO_Type
);