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
)
64 if (PyErr_WarnEx(PyExc_RuntimeWarning
,
65 "Trying to close unclosable fd!", 3) < 0) {
70 errno
= internal_close(self
);
72 PyErr_SetFromErrno(PyExc_IOError
);
80 fileio_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kews
)
84 assert(type
!= NULL
&& type
->tp_alloc
!= NULL
);
86 self
= (PyFileIOObject
*) type
->tp_alloc(type
, 0);
89 self
->weakreflist
= NULL
;
92 return (PyObject
*) self
;
95 /* On Unix, open will succeed for directories.
96 In Python, there should be no file objects referring to
97 directories, so we need a check. */
100 dircheck(PyFileIOObject
* self
)
102 #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
106 if (fstat(self
->fd
, &buf
) == 0 && S_ISDIR(buf
.st_mode
)) {
107 char *msg
= strerror(EISDIR
);
109 internal_close(self
);
111 exc
= PyObject_CallFunction(PyExc_IOError
, "(is)",
113 PyErr_SetObject(PyExc_IOError
, exc
);
123 fileio_init(PyObject
*oself
, PyObject
*args
, PyObject
*kwds
)
125 PyFileIOObject
*self
= (PyFileIOObject
*) oself
;
126 static char *kwlist
[] = {"file", "mode", "closefd", NULL
};
131 Py_UNICODE
*widename
= NULL
;
134 int rwa
= 0, plus
= 0, append
= 0;
139 assert(PyFileIO_Check(oself
));
141 /* Have to close the existing file first. */
142 if (internal_close(self
) < 0)
146 if (PyArg_ParseTupleAndKeywords(args
, kwds
, "i|si:fileio",
147 kwlist
, &fd
, &mode
, &closefd
)) {
149 PyErr_SetString(PyExc_ValueError
,
150 "Negative filedescriptor");
157 #ifdef Py_WIN_WIDE_FILENAMES
158 if (GetVersion() < 0x80000000) {
159 /* On NT, so wide API available */
161 if (PyArg_ParseTupleAndKeywords(args
, kwds
, "U|si:fileio",
162 kwlist
, &po
, &mode
, &closefd
)
164 widename
= PyUnicode_AS_UNICODE(po
);
166 /* Drop the argument parsing error as narrow
167 strings are also valid. */
171 if (widename
== NULL
)
174 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "et|si:fileio",
176 Py_FileSystemDefaultEncoding
,
177 &name
, &mode
, &closefd
))
182 self
->readable
= self
->writable
= 0;
190 PyErr_SetString(PyExc_ValueError
,
191 "Must have exactly one of read/write/append mode");
202 flags
|= O_CREAT
| O_TRUNC
;
215 self
->readable
= self
->writable
= 1;
219 PyErr_Format(PyExc_ValueError
,
220 "invalid mode: %.200s", mode
);
228 if (self
->readable
&& self
->writable
)
230 else if (self
->readable
)
246 self
->closefd
= closefd
;
251 PyErr_SetString(PyExc_ValueError
,
252 "Cannot use closefd=True with file name");
256 Py_BEGIN_ALLOW_THREADS
259 if (widename
!= NULL
)
260 self
->fd
= _wopen(widename
, flags
, 0666);
263 self
->fd
= open(name
, flags
, 0666);
267 PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError
, widename
);
269 PyErr_SetFromErrnoWithFilename(PyExc_IOError
, name
);
273 if(dircheck(self
) < 0)
288 fileio_dealloc(PyFileIOObject
*self
)
290 if (self
->weakreflist
!= NULL
)
291 PyObject_ClearWeakRefs((PyObject
*) self
);
293 if (self
->fd
>= 0 && self
->closefd
) {
294 errno
= internal_close(self
);
296 PySys_WriteStderr("close failed: [Errno %d] %s\n",
297 errno
, strerror(errno
));
301 Py_TYPE(self
)->tp_free((PyObject
*)self
);
307 PyErr_SetString(PyExc_ValueError
, "I/O operation on closed file");
312 err_mode(char *action
)
314 PyErr_Format(PyExc_ValueError
, "File not open for %s", action
);
319 fileio_fileno(PyFileIOObject
*self
)
323 return PyInt_FromLong((long) self
->fd
);
327 fileio_readable(PyFileIOObject
*self
)
331 return PyBool_FromLong((long) self
->readable
);
335 fileio_writable(PyFileIOObject
*self
)
339 return PyBool_FromLong((long) self
->writable
);
343 fileio_seekable(PyFileIOObject
*self
)
347 if (self
->seekable
< 0) {
349 Py_BEGIN_ALLOW_THREADS
350 ret
= lseek(self
->fd
, 0, SEEK_CUR
);
357 return PyBool_FromLong((long) self
->seekable
);
361 fileio_readinto(PyFileIOObject
*self
, PyObject
*args
)
369 return err_mode("reading");
371 if (!PyArg_ParseTuple(args
, "w*", &pbuf
))
374 Py_BEGIN_ALLOW_THREADS
376 n
= read(self
->fd
, pbuf
.buf
, pbuf
.len
);
378 PyBuffer_Release(&pbuf
);
382 PyErr_SetFromErrno(PyExc_IOError
);
386 return PyLong_FromSsize_t(n
);
389 #define DEFAULT_BUFFER_SIZE (8*1024)
392 fileio_readall(PyFileIOObject
*self
)
395 Py_ssize_t total
= 0;
398 result
= PyString_FromStringAndSize(NULL
, DEFAULT_BUFFER_SIZE
);
403 Py_ssize_t newsize
= total
+ DEFAULT_BUFFER_SIZE
;
404 if (PyString_GET_SIZE(result
) < newsize
) {
405 if (_PyString_Resize(&result
, newsize
) < 0) {
414 Py_BEGIN_ALLOW_THREADS
417 PyString_AS_STRING(result
) + total
,
425 if (errno
== EAGAIN
) {
430 PyErr_SetFromErrno(PyExc_IOError
);
436 if (PyString_GET_SIZE(result
) > total
) {
437 if (_PyString_Resize(&result
, total
) < 0) {
438 /* This should never happen, but just in case */
447 fileio_read(PyFileIOObject
*self
, PyObject
*args
)
451 Py_ssize_t size
= -1;
457 return err_mode("reading");
459 if (!PyArg_ParseTuple(args
, "|n", &size
))
463 return fileio_readall(self
);
466 bytes
= PyString_FromStringAndSize(NULL
, size
);
469 ptr
= PyString_AS_STRING(bytes
);
471 Py_BEGIN_ALLOW_THREADS
473 n
= read(self
->fd
, ptr
, size
);
479 PyErr_SetFromErrno(PyExc_IOError
);
484 if (_PyString_Resize(&bytes
, n
) < 0) {
490 return (PyObject
*) bytes
;
494 fileio_write(PyFileIOObject
*self
, PyObject
*args
)
502 return err_mode("writing");
504 if (!PyArg_ParseTuple(args
, "s*", &pbuf
))
507 Py_BEGIN_ALLOW_THREADS
509 n
= write(self
->fd
, pbuf
.buf
, pbuf
.len
);
512 PyBuffer_Release(&pbuf
);
517 PyErr_SetFromErrno(PyExc_IOError
);
521 return PyLong_FromSsize_t(n
);
524 /* XXX Windows support below is likely incomplete */
526 #if defined(MS_WIN64) || defined(MS_WINDOWS)
527 typedef PY_LONG_LONG Py_off_t
;
529 typedef off_t Py_off_t
;
532 /* Cribbed from posix_lseek() */
534 portable_lseek(int fd
, PyObject
*posobj
, int whence
)
539 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
542 case 0: whence
= SEEK_SET
; break;
545 case 1: whence
= SEEK_CUR
; break;
548 case 2: whence
= SEEK_END
; break;
551 #endif /* SEEK_SET */
556 if(PyFloat_Check(posobj
)) {
557 PyErr_SetString(PyExc_TypeError
, "an integer is required");
560 #if defined(HAVE_LARGEFILE_SUPPORT)
561 pos
= PyLong_AsLongLong(posobj
);
563 pos
= PyLong_AsLong(posobj
);
565 if (PyErr_Occurred())
569 Py_BEGIN_ALLOW_THREADS
570 #if defined(MS_WIN64) || defined(MS_WINDOWS)
571 res
= _lseeki64(fd
, pos
, whence
);
573 res
= lseek(fd
, pos
, whence
);
577 return PyErr_SetFromErrno(PyExc_IOError
);
579 #if defined(HAVE_LARGEFILE_SUPPORT)
580 return PyLong_FromLongLong(res
);
582 return PyLong_FromLong(res
);
587 fileio_seek(PyFileIOObject
*self
, PyObject
*args
)
595 if (!PyArg_ParseTuple(args
, "O|i", &posobj
, &whence
))
598 return portable_lseek(self
->fd
, posobj
, whence
);
602 fileio_tell(PyFileIOObject
*self
, PyObject
*args
)
607 return portable_lseek(self
->fd
, NULL
, 1);
610 #ifdef HAVE_FTRUNCATE
612 fileio_truncate(PyFileIOObject
*self
, PyObject
*args
)
614 PyObject
*posobj
= NULL
;
623 return err_mode("writing");
625 if (!PyArg_ParseTuple(args
, "|O", &posobj
))
628 if (posobj
== Py_None
|| posobj
== NULL
) {
629 /* Get the current position. */
630 posobj
= portable_lseek(fd
, NULL
, 1);
635 /* Move to the position to be truncated. */
636 posobj
= portable_lseek(fd
, posobj
, 0);
639 #if defined(HAVE_LARGEFILE_SUPPORT)
640 pos
= PyLong_AsLongLong(posobj
);
642 pos
= PyLong_AsLong(posobj
);
644 if (PyErr_Occurred())
648 /* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
649 so don't even try using it. */
653 /* Truncate. Note that this may grow the file! */
654 Py_BEGIN_ALLOW_THREADS
656 hFile
= (HANDLE
)_get_osfhandle(fd
);
657 ret
= hFile
== (HANDLE
)-1;
659 ret
= SetEndOfFile(hFile
) == 0;
666 Py_BEGIN_ALLOW_THREADS
668 ret
= ftruncate(fd
, pos
);
670 #endif /* !MS_WINDOWS */
673 PyErr_SetFromErrno(PyExc_IOError
);
682 mode_string(PyFileIOObject
*self
)
684 if (self
->readable
) {
695 fileio_repr(PyFileIOObject
*self
)
698 return PyString_FromFormat("_fileio._FileIO(-1)");
700 return PyString_FromFormat("_fileio._FileIO(%d, '%s')",
701 self
->fd
, mode_string(self
));
705 fileio_isatty(PyFileIOObject
*self
)
711 Py_BEGIN_ALLOW_THREADS
712 res
= isatty(self
->fd
);
714 return PyBool_FromLong(res
);
718 PyDoc_STRVAR(fileio_doc
,
719 "file(name: str[, mode: str]) -> file IO object\n"
721 "Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n"
722 "writing or appending. The file will be created if it doesn't exist\n"
723 "when opened for writing or appending; it will be truncated when\n"
724 "opened for writing. Add a '+' to the mode to allow simultaneous\n"
725 "reading and writing.");
727 PyDoc_STRVAR(read_doc
,
728 "read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"
730 "Only makes one system call, so less data may be returned than requested\n"
731 "In non-blocking mode, returns None if no data is available.\n"
732 "On end-of-file, returns ''.");
734 PyDoc_STRVAR(readall_doc
,
735 "readall() -> bytes. read all data from the file, returned as bytes.\n"
737 "In non-blocking mode, returns as much as is immediately available,\n"
738 "or None if no data is available. On end-of-file, returns ''.");
740 PyDoc_STRVAR(write_doc
,
741 "write(b: bytes) -> int. Write bytes b to file, return number written.\n"
743 "Only makes one system call, so not all of the data may be written.\n"
744 "The number of bytes actually written is returned.");
746 PyDoc_STRVAR(fileno_doc
,
747 "fileno() -> int. \"file descriptor\".\n"
749 "This is needed for lower-level file interfaces, such the fcntl module.");
751 PyDoc_STRVAR(seek_doc
,
752 "seek(offset: int[, whence: int]) -> None. Move to new file position.\n"
754 "Argument offset is a byte count. Optional argument whence defaults to\n"
755 "0 (offset from start of file, offset should be >= 0); other values are 1\n"
756 "(move relative to current position, positive or negative), and 2 (move\n"
757 "relative to end of file, usually negative, although many platforms allow\n"
758 "seeking beyond the end of a file)."
760 "Note that not all file objects are seekable.");
762 #ifdef HAVE_FTRUNCATE
763 PyDoc_STRVAR(truncate_doc
,
764 "truncate([size: int]) -> None. Truncate the file to at most size bytes.\n"
766 "Size defaults to the current file position, as returned by tell()."
767 "The current file position is changed to the value of size.");
770 PyDoc_STRVAR(tell_doc
,
771 "tell() -> int. Current file position");
773 PyDoc_STRVAR(readinto_doc
,
774 "readinto() -> Undocumented. Don't use this; it may go away.");
776 PyDoc_STRVAR(close_doc
,
777 "close() -> None. Close the file.\n"
779 "A closed file cannot be used for further I/O operations. close() may be\n"
780 "called more than once without error. Changes the fileno to -1.");
782 PyDoc_STRVAR(isatty_doc
,
783 "isatty() -> bool. True if the file is connected to a tty device.");
785 PyDoc_STRVAR(seekable_doc
,
786 "seekable() -> bool. True if file supports random-access.");
788 PyDoc_STRVAR(readable_doc
,
789 "readable() -> bool. True if file was opened in a read mode.");
791 PyDoc_STRVAR(writable_doc
,
792 "writable() -> bool. True if file was opened in a write mode.");
794 static PyMethodDef fileio_methods
[] = {
795 {"read", (PyCFunction
)fileio_read
, METH_VARARGS
, read_doc
},
796 {"readall", (PyCFunction
)fileio_readall
, METH_NOARGS
, readall_doc
},
797 {"readinto", (PyCFunction
)fileio_readinto
, METH_VARARGS
, readinto_doc
},
798 {"write", (PyCFunction
)fileio_write
, METH_VARARGS
, write_doc
},
799 {"seek", (PyCFunction
)fileio_seek
, METH_VARARGS
, seek_doc
},
800 {"tell", (PyCFunction
)fileio_tell
, METH_VARARGS
, tell_doc
},
801 #ifdef HAVE_FTRUNCATE
802 {"truncate", (PyCFunction
)fileio_truncate
, METH_VARARGS
, truncate_doc
},
804 {"close", (PyCFunction
)fileio_close
, METH_NOARGS
, close_doc
},
805 {"seekable", (PyCFunction
)fileio_seekable
, METH_NOARGS
, seekable_doc
},
806 {"readable", (PyCFunction
)fileio_readable
, METH_NOARGS
, readable_doc
},
807 {"writable", (PyCFunction
)fileio_writable
, METH_NOARGS
, writable_doc
},
808 {"fileno", (PyCFunction
)fileio_fileno
, METH_NOARGS
, fileno_doc
},
809 {"isatty", (PyCFunction
)fileio_isatty
, METH_NOARGS
, isatty_doc
},
810 {NULL
, NULL
} /* sentinel */
813 /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
816 get_closed(PyFileIOObject
*self
, void *closure
)
818 return PyBool_FromLong((long)(self
->fd
< 0));
822 get_mode(PyFileIOObject
*self
, void *closure
)
824 return PyString_FromString(mode_string(self
));
827 static PyGetSetDef fileio_getsetlist
[] = {
828 {"closed", (getter
)get_closed
, NULL
, "True if the file is closed"},
829 {"mode", (getter
)get_mode
, NULL
, "String giving the file mode"},
833 PyTypeObject PyFileIO_Type
= {
834 PyVarObject_HEAD_INIT(NULL
, 0)
836 sizeof(PyFileIOObject
),
838 (destructor
)fileio_dealloc
, /* tp_dealloc */
843 (reprfunc
)fileio_repr
, /* tp_repr */
844 0, /* tp_as_number */
845 0, /* tp_as_sequence */
846 0, /* tp_as_mapping */
850 PyObject_GenericGetAttr
, /* tp_getattro */
852 0, /* tp_as_buffer */
853 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
854 fileio_doc
, /* tp_doc */
857 0, /* tp_richcompare */
858 offsetof(PyFileIOObject
, weakreflist
), /* tp_weaklistoffset */
861 fileio_methods
, /* tp_methods */
863 fileio_getsetlist
, /* tp_getset */
866 0, /* tp_descr_get */
867 0, /* tp_descr_set */
868 0, /* tp_dictoffset */
869 fileio_init
, /* tp_init */
870 PyType_GenericAlloc
, /* tp_alloc */
871 fileio_new
, /* tp_new */
872 PyObject_Del
, /* tp_free */
875 static PyMethodDef module_methods
[] = {
882 PyObject
*m
; /* a module object */
884 m
= Py_InitModule3("_fileio", module_methods
,
885 "Fast implementation of io.FileIO.");
888 if (PyType_Ready(&PyFileIO_Type
) < 0)
890 Py_INCREF(&PyFileIO_Type
);
891 PyModule_AddObject(m
, "_FileIO", (PyObject
*) &PyFileIO_Type
);