summaryrefslogtreecommitdiffstats
path: root/Modules/_io/fileio.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_io/fileio.c')
-rw-r--r--Modules/_io/fileio.c650
1 files changed, 292 insertions, 358 deletions
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index 74508a7..0894ca4 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -43,6 +43,19 @@
#define SMALLCHUNK BUFSIZ
#endif
+/*[clinic input]
+module _io
+class _io.FileIO "fileio *" "&PyFileIO_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1c77708b41fda70c]*/
+
+/*[python input]
+class io_ssize_t_converter(CConverter):
+ type = 'Py_ssize_t'
+ converter = '_PyIO_ConvertSsize_t'
+[python start generated code]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/
+
typedef struct {
PyObject_HEAD
int fd;
@@ -53,6 +66,7 @@ typedef struct {
signed int seekable : 2; /* -1 means unknown */
unsigned int closefd : 1;
char finalizing;
+ unsigned int blksize;
PyObject *weakreflist;
PyObject *dict;
} fileio;
@@ -106,9 +120,11 @@ internal_close(fileio *self)
/* fd is accessible and someone else may have closed it */
if (_PyVerify_fd(fd)) {
Py_BEGIN_ALLOW_THREADS
+ _Py_BEGIN_SUPPRESS_IPH
err = close(fd);
if (err < 0)
save_errno = errno;
+ _Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS
} else {
save_errno = errno;
@@ -123,8 +139,18 @@ internal_close(fileio *self)
return 0;
}
+/*[clinic input]
+_io.FileIO.close
+
+Close the file.
+
+A closed file cannot be used for further I/O operations. close() may be
+called more than once without error.
+[clinic start generated code]*/
+
static PyObject *
-fileio_close(fileio *self)
+_io_FileIO_close_impl(fileio *self)
+/*[clinic end generated code: output=7737a319ef3bad0b input=f35231760d54a522]*/
{
PyObject *res;
PyObject *exc, *val, *tb;
@@ -168,6 +194,7 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->writable = 0;
self->appending = 0;
self->seekable = -1;
+ self->blksize = 0;
self->closefd = 1;
self->weakreflist = NULL;
}
@@ -175,57 +202,40 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return (PyObject *) self;
}
-/* On Unix, open will succeed for directories.
- In Python, there should be no file objects referring to
- directories, so we need a check. */
-
-static int
-dircheck(fileio* self, PyObject *nameobj)
-{
-#if defined(HAVE_FSTAT) && defined(S_ISDIR) && defined(EISDIR)
- struct stat buf;
- if (self->fd < 0)
- return 0;
- if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
- errno = EISDIR;
- PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj);
- return -1;
- }
-#endif
- return 0;
-}
-
-static int
-check_fd(int fd)
-{
-#if defined(HAVE_FSTAT)
- struct stat buf;
- if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) {
- PyObject *exc;
- char *msg = strerror(EBADF);
- exc = PyObject_CallFunction(PyExc_OSError, "(is)",
- EBADF, msg);
- PyErr_SetObject(PyExc_OSError, exc);
- Py_XDECREF(exc);
- return -1;
- }
-#endif
- return 0;
-}
-
#ifdef O_CLOEXEC
extern int _Py_open_cloexec_works;
#endif
+/*[clinic input]
+_io.FileIO.__init__
+ file as nameobj: object
+ mode: str = "r"
+ closefd: int(c_default="1") = True
+ opener: object = None
+
+Open a file.
+
+The mode can be 'r' (default), 'w', 'x' or 'a' for reading,
+writing, exclusive creation or appending. The file will be created if it
+doesn't exist when opened for writing or appending; it will be truncated
+when opened for writing. A FileExistsError will be raised if it already
+exists when opened for creating. Opening a file for creating implies
+writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode
+to allow simultaneous reading and writing. A custom opener can be used by
+passing a callable as *opener*. The underlying file descriptor for the file
+object is then obtained by calling opener with (*name*, *flags*).
+*opener* must return an open file descriptor (passing os.open as *opener*
+results in functionality similar to passing None).
+[clinic start generated code]*/
+
static int
-fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
+_io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
+ int closefd, PyObject *opener)
+/*[clinic end generated code: output=23413f68e6484bbd input=193164e293d6c097]*/
{
- fileio *self = (fileio *) oself;
- static char *kwlist[] = {"file", "mode", "closefd", "opener", NULL};
const char *name = NULL;
- PyObject *nameobj, *stringobj = NULL, *opener = Py_None;
- char *mode = "r";
- char *s;
+ PyObject *stringobj = NULL;
+ const char *s;
#ifdef MS_WINDOWS
Py_UNICODE *widename = NULL;
#endif
@@ -233,15 +243,16 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
int rwa = 0, plus = 0;
int flags = 0;
int fd = -1;
- int closefd = 1;
int fd_is_own = 0;
#ifdef O_CLOEXEC
int *atomic_flag_works = &_Py_open_cloexec_works;
#elif !defined(MS_WINDOWS)
int *atomic_flag_works = NULL;
#endif
+ struct _Py_stat_struct fdfstat;
+ int async_err = 0;
- assert(PyFileIO_Check(oself));
+ assert(PyFileIO_Check(self));
if (self->fd >= 0) {
if (self->closefd) {
/* Have to close the existing file first. */
@@ -252,11 +263,6 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
self->fd = -1;
}
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|siO:fileio",
- kwlist, &nameobj, &mode, &closefd,
- &opener))
- return -1;
-
if (PyFloat_Check(nameobj)) {
PyErr_SetString(PyExc_TypeError,
"integer argument expected, got float");
@@ -280,7 +286,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
if (widename == NULL)
return -1;
if (wcslen(widename) != length) {
- PyErr_SetString(PyExc_TypeError, "embedded NUL character");
+ PyErr_SetString(PyExc_ValueError, "embedded null character");
return -1;
}
} else
@@ -366,8 +372,6 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
#endif
if (fd >= 0) {
- if (check_fd(fd))
- goto error;
self->fd = fd;
self->closefd = closefd;
}
@@ -381,15 +385,20 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
errno = 0;
if (opener == Py_None) {
- Py_BEGIN_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
#ifdef MS_WINDOWS
- if (widename != NULL)
- self->fd = _wopen(widename, flags, 0666);
- else
+ if (widename != NULL)
+ self->fd = _wopen(widename, flags, 0666);
+ else
#endif
- self->fd = open(name, flags, 0666);
+ self->fd = open(name, flags, 0666);
+ Py_END_ALLOW_THREADS
+ } while (self->fd < 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
- Py_END_ALLOW_THREADS
+ if (async_err)
+ goto error;
}
else {
PyObject *fdobj;
@@ -427,8 +436,24 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
goto error;
#endif
}
- if (dircheck(self, nameobj) < 0)
+
+ self->blksize = DEFAULT_BUFFER_SIZE;
+ if (_Py_fstat(self->fd, &fdfstat) < 0)
+ goto error;
+#if defined(S_ISDIR) && defined(EISDIR)
+ /* On Unix, open will succeed for directories.
+ In Python, there should be no file objects referring to
+ directories, so we need a check. */
+ if (S_ISDIR(fdfstat.st_mode)) {
+ errno = EISDIR;
+ PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj);
goto error;
+ }
+#endif /* defined(S_ISDIR) */
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+ if (fdfstat.st_blksize > 1)
+ self->blksize = fdfstat.st_blksize;
+#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
#if defined(MS_WINDOWS) || defined(__CYGWIN__)
/* don't translate newlines (\r\n <=> \n) */
@@ -506,32 +531,60 @@ err_mode(char *action)
return NULL;
}
+/*[clinic input]
+_io.FileIO.fileno
+
+Return the underlying file descriptor (an integer).
+[clinic start generated code]*/
+
static PyObject *
-fileio_fileno(fileio *self)
+_io_FileIO_fileno_impl(fileio *self)
+/*[clinic end generated code: output=a9626ce5398ece90 input=0b9b2de67335ada3]*/
{
if (self->fd < 0)
return err_closed();
return PyLong_FromLong((long) self->fd);
}
+/*[clinic input]
+_io.FileIO.readable
+
+True if file was opened in a read mode.
+[clinic start generated code]*/
+
static PyObject *
-fileio_readable(fileio *self)
+_io_FileIO_readable_impl(fileio *self)
+/*[clinic end generated code: output=640744a6150fe9ba input=a3fdfed6eea721c5]*/
{
if (self->fd < 0)
return err_closed();
return PyBool_FromLong((long) self->readable);
}
+/*[clinic input]
+_io.FileIO.writable
+
+True if file was opened in a write mode.
+[clinic start generated code]*/
+
static PyObject *
-fileio_writable(fileio *self)
+_io_FileIO_writable_impl(fileio *self)
+/*[clinic end generated code: output=96cefc5446e89977 input=c204a808ca2e1748]*/
{
if (self->fd < 0)
return err_closed();
return PyBool_FromLong((long) self->writable);
}
+/*[clinic input]
+_io.FileIO.seekable
+
+True if file supports random-access.
+[clinic start generated code]*/
+
static PyObject *
-fileio_seekable(fileio *self)
+_io_FileIO_seekable_impl(fileio *self)
+/*[clinic end generated code: output=47909ca0a42e9287 input=c8e5554d2fd63c7f]*/
{
if (self->fd < 0)
return err_closed();
@@ -548,11 +601,19 @@ fileio_seekable(fileio *self)
return PyBool_FromLong((long) self->seekable);
}
+/*[clinic input]
+_io.FileIO.readinto
+ buffer: Py_buffer(types={'rwbuffer'})
+ /
+
+Same as RawIOBase.readinto().
+[clinic start generated code]*/
+
static PyObject *
-fileio_readinto(fileio *self, PyObject *args)
+_io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer)
+/*[clinic end generated code: output=b01a5a22c8415cb4 input=5edd8327498d468c]*/
{
- Py_buffer pbuf;
- Py_ssize_t n, len;
+ Py_ssize_t n;
int err;
if (self->fd < 0)
@@ -560,48 +621,21 @@ fileio_readinto(fileio *self, PyObject *args)
if (!self->readable)
return err_mode("reading");
- if (!PyArg_ParseTuple(args, "w*", &pbuf))
- return NULL;
-
- if (_PyVerify_fd(self->fd)) {
- len = pbuf.len;
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
-#ifdef MS_WINDOWS
- if (len > INT_MAX)
- len = INT_MAX;
- n = read(self->fd, pbuf.buf, (int)len);
-#else
- n = read(self->fd, pbuf.buf, len);
-#endif
- Py_END_ALLOW_THREADS
- } else
- n = -1;
+ n = _Py_read(self->fd, buffer->buf, buffer->len);
+ /* copy errno because PyBuffer_Release() can indirectly modify it */
err = errno;
- PyBuffer_Release(&pbuf);
- if (n < 0) {
- if (err == EAGAIN)
+
+ if (n == -1) {
+ if (err == EAGAIN) {
+ PyErr_Clear();
Py_RETURN_NONE;
- errno = err;
- PyErr_SetFromErrno(PyExc_IOError);
+ }
return NULL;
}
return PyLong_FromSsize_t(n);
}
-#ifndef HAVE_FSTAT
-
-static PyObject *
-fileio_readall(fileio *self)
-{
- _Py_IDENTIFIER(readall);
- return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type,
- &PyId_readall, "O", self);
-}
-
-#else
-
static size_t
new_buffersize(fileio *self, size_t currentsize)
{
@@ -621,10 +655,20 @@ new_buffersize(fileio *self, size_t currentsize)
return addend + currentsize;
}
+/*[clinic input]
+_io.FileIO.readall
+
+Read all data from the file, returned as bytes.
+
+In non-blocking mode, returns as much as is immediately available,
+or None if no data is available. Return an empty bytes object at EOF.
+[clinic start generated code]*/
+
static PyObject *
-fileio_readall(fileio *self)
+_io_FileIO_readall_impl(fileio *self)
+/*[clinic end generated code: output=faa0292b213b4022 input=dbdc137f55602834]*/
{
- struct stat st;
+ struct _Py_stat_struct status;
Py_off_t pos, end;
PyObject *result;
Py_ssize_t bytes_read = 0;
@@ -636,13 +680,16 @@ fileio_readall(fileio *self)
if (!_PyVerify_fd(self->fd))
return PyErr_SetFromErrno(PyExc_IOError);
+ _Py_BEGIN_SUPPRESS_IPH
#ifdef MS_WINDOWS
pos = _lseeki64(self->fd, 0L, SEEK_CUR);
#else
pos = lseek(self->fd, 0L, SEEK_CUR);
#endif
- if (fstat(self->fd, &st) == 0)
- end = st.st_size;
+ _Py_END_SUPPRESS_IPH
+
+ if (_Py_fstat_noraise(self->fd, &status) == 0)
+ end = status.st_size;
else
end = (Py_off_t)-1;
@@ -676,35 +723,22 @@ fileio_readall(fileio *self)
return NULL;
}
}
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
- n = bufsize - bytes_read;
-#ifdef MS_WINDOWS
- if (n > INT_MAX)
- n = INT_MAX;
- n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n);
-#else
- n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n);
-#endif
- Py_END_ALLOW_THREADS
+
+ n = _Py_read(self->fd,
+ PyBytes_AS_STRING(result) + bytes_read,
+ bufsize - bytes_read);
+
if (n == 0)
break;
- if (n < 0) {
- if (errno == EINTR) {
- if (PyErr_CheckSignals()) {
- Py_DECREF(result);
- return NULL;
- }
- continue;
- }
+ if (n == -1) {
if (errno == EAGAIN) {
+ PyErr_Clear();
if (bytes_read > 0)
break;
Py_DECREF(result);
Py_RETURN_NONE;
}
Py_DECREF(result);
- PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
bytes_read += n;
@@ -718,14 +752,24 @@ fileio_readall(fileio *self)
return result;
}
-#endif /* HAVE_FSTAT */
+/*[clinic input]
+_io.FileIO.read
+ size: io_ssize_t = -1
+ /
+
+Read at most size bytes, returned as bytes.
+
+Only makes one system call, so less data may be returned than requested.
+In non-blocking mode, returns None if no data is available.
+Return an empty bytes object at EOF.
+[clinic start generated code]*/
static PyObject *
-fileio_read(fileio *self, PyObject *args)
+_io_FileIO_read_impl(fileio *self, Py_ssize_t size)
+/*[clinic end generated code: output=42528d39dd0ca641 input=5c6caa5490c13a9b]*/
{
char *ptr;
Py_ssize_t n;
- Py_ssize_t size = -1;
PyObject *bytes;
if (self->fd < 0)
@@ -733,41 +777,29 @@ fileio_read(fileio *self, PyObject *args)
if (!self->readable)
return err_mode("reading");
- if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size))
- return NULL;
-
- if (size < 0) {
- return fileio_readall(self);
- }
+ if (size < 0)
+ return _io_FileIO_readall_impl(self);
#ifdef MS_WINDOWS
+ /* On Windows, the count parameter of read() is an int */
if (size > INT_MAX)
size = INT_MAX;
#endif
+
bytes = PyBytes_FromStringAndSize(NULL, size);
if (bytes == NULL)
return NULL;
ptr = PyBytes_AS_STRING(bytes);
- if (_PyVerify_fd(self->fd)) {
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
-#ifdef MS_WINDOWS
- n = read(self->fd, ptr, (int)size);
-#else
- n = read(self->fd, ptr, size);
-#endif
- Py_END_ALLOW_THREADS
- } else
- n = -1;
-
- if (n < 0) {
+ n = _Py_read(self->fd, ptr, size);
+ if (n == -1) {
+ /* copy errno because Py_DECREF() can indirectly modify it */
int err = errno;
Py_DECREF(bytes);
- if (err == EAGAIN)
+ if (err == EAGAIN) {
+ PyErr_Clear();
Py_RETURN_NONE;
- errno = err;
- PyErr_SetFromErrno(PyExc_IOError);
+ }
return NULL;
}
@@ -781,11 +813,23 @@ fileio_read(fileio *self, PyObject *args)
return (PyObject *) bytes;
}
+/*[clinic input]
+_io.FileIO.write
+ b: Py_buffer
+ /
+
+Write bytes b to file, return number written.
+
+Only makes one system call, so not all of the data may be written.
+The number of bytes actually written is returned. In non-blocking mode,
+returns None if the write would block.
+[clinic start generated code]*/
+
static PyObject *
-fileio_write(fileio *self, PyObject *args)
+_io_FileIO_write_impl(fileio *self, Py_buffer *b)
+/*[clinic end generated code: output=b4059db3d363a2f7 input=ffbd8834f447ac31]*/
{
- Py_buffer pbuf;
- Py_ssize_t n, len;
+ Py_ssize_t n;
int err;
if (self->fd < 0)
@@ -793,39 +837,15 @@ fileio_write(fileio *self, PyObject *args)
if (!self->writable)
return err_mode("writing");
- if (!PyArg_ParseTuple(args, "y*", &pbuf))
- return NULL;
-
- if (_PyVerify_fd(self->fd)) {
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
- len = pbuf.len;
-#ifdef MS_WINDOWS
- if (len > 32767 && isatty(self->fd)) {
- /* Issue #11395: the Windows console returns an error (12: not
- enough space error) on writing into stdout if stdout mode is
- binary and the length is greater than 66,000 bytes (or less,
- depending on heap usage). */
- len = 32767;
- }
- else if (len > INT_MAX)
- len = INT_MAX;
- n = write(self->fd, pbuf.buf, (int)len);
-#else
- n = write(self->fd, pbuf.buf, len);
-#endif
- Py_END_ALLOW_THREADS
- } else
- n = -1;
+ n = _Py_write(self->fd, b->buf, b->len);
+ /* copy errno because PyBuffer_Release() can indirectly modify it */
err = errno;
- PyBuffer_Release(&pbuf);
-
if (n < 0) {
- if (err == EAGAIN)
+ if (err == EAGAIN) {
+ PyErr_Clear();
Py_RETURN_NONE;
- errno = err;
- PyErr_SetFromErrno(PyExc_IOError);
+ }
return NULL;
}
@@ -873,11 +893,13 @@ portable_lseek(int fd, PyObject *posobj, int whence)
if (_PyVerify_fd(fd)) {
Py_BEGIN_ALLOW_THREADS
+ _Py_BEGIN_SUPPRESS_IPH
#ifdef MS_WINDOWS
res = _lseeki64(fd, pos, whence);
#else
res = lseek(fd, pos, whence);
#endif
+ _Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS
} else
res = -1;
@@ -891,23 +913,44 @@ portable_lseek(int fd, PyObject *posobj, int whence)
#endif
}
+/*[clinic input]
+_io.FileIO.seek
+ pos: object
+ whence: int = 0
+ /
+
+Move to new file position and return the file position.
+
+Argument offset is a byte count. Optional argument whence defaults to
+SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values
+are SEEK_CUR or 1 (move relative to current position, positive or negative),
+and SEEK_END or 2 (move relative to end of file, usually negative, although
+many platforms allow seeking beyond the end of a file).
+
+Note that not all file objects are seekable.
+[clinic start generated code]*/
+
static PyObject *
-fileio_seek(fileio *self, PyObject *args)
+_io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence)
+/*[clinic end generated code: output=c976acdf054e6655 input=0439194b0774d454]*/
{
- PyObject *posobj;
- int whence = 0;
-
if (self->fd < 0)
return err_closed();
- if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))
- return NULL;
-
- return portable_lseek(self->fd, posobj, whence);
+ return portable_lseek(self->fd, pos, whence);
}
+/*[clinic input]
+_io.FileIO.tell
+
+Current file position.
+
+Can raise OSError for non seekable files.
+[clinic start generated code]*/
+
static PyObject *
-fileio_tell(fileio *self, PyObject *args)
+_io_FileIO_tell_impl(fileio *self)
+/*[clinic end generated code: output=ffe2147058809d0b input=807e24ead4cec2f9]*/
{
if (self->fd < 0)
return err_closed();
@@ -916,13 +959,22 @@ fileio_tell(fileio *self, PyObject *args)
}
#ifdef HAVE_FTRUNCATE
+/*[clinic input]
+_io.FileIO.truncate
+ size as posobj: object = NULL
+ /
+
+Truncate the file to at most size bytes and return the truncated size.
+
+Size defaults to the current file position, as returned by tell().
+The current file position is changed to the value of size.
+[clinic start generated code]*/
+
static PyObject *
-fileio_truncate(fileio *self, PyObject *args)
+_io_FileIO_truncate_impl(fileio *self, PyObject *posobj)
+/*[clinic end generated code: output=e49ca7a916c176fa input=9026af44686b7318]*/
{
- PyObject *posobj = NULL; /* the new size wanted by the user */
-#ifndef MS_WINDOWS
Py_off_t pos;
-#endif
int ret;
int fd;
@@ -932,9 +984,6 @@ fileio_truncate(fileio *self, PyObject *args)
if (!self->writable)
return err_mode("writing");
- if (!PyArg_ParseTuple(args, "|O", &posobj))
- return NULL;
-
if (posobj == Py_None || posobj == NULL) {
/* Get the current position. */
posobj = portable_lseek(fd, NULL, 1);
@@ -945,52 +994,6 @@ fileio_truncate(fileio *self, PyObject *args)
Py_INCREF(posobj);
}
-#ifdef MS_WINDOWS
- /* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
- so don't even try using it. */
- {
- PyObject *oldposobj, *tempposobj;
- HANDLE hFile;
-
- /* we save the file pointer position */
- oldposobj = portable_lseek(fd, NULL, 1);
- if (oldposobj == NULL) {
- Py_DECREF(posobj);
- return NULL;
- }
-
- /* we then move to the truncation position */
- tempposobj = portable_lseek(fd, posobj, 0);
- if (tempposobj == NULL) {
- Py_DECREF(oldposobj);
- Py_DECREF(posobj);
- return NULL;
- }
- Py_DECREF(tempposobj);
-
- /* Truncate. Note that this may grow the file! */
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
- hFile = (HANDLE)_get_osfhandle(fd);
- ret = hFile == (HANDLE)-1; /* testing for INVALID_HANDLE value */
- if (ret == 0) {
- ret = SetEndOfFile(hFile) == 0;
- if (ret)
- errno = EACCES;
- }
- Py_END_ALLOW_THREADS
-
- /* we restore the file pointer position in any case */
- tempposobj = portable_lseek(fd, oldposobj, 0);
- Py_DECREF(oldposobj);
- if (tempposobj == NULL) {
- Py_DECREF(posobj);
- return NULL;
- }
- Py_DECREF(tempposobj);
- }
-#else
-
#if defined(HAVE_LARGEFILE_SUPPORT)
pos = PyLong_AsLongLong(posobj);
#else
@@ -1002,12 +1005,16 @@ fileio_truncate(fileio *self, PyObject *args)
}
Py_BEGIN_ALLOW_THREADS
+ _Py_BEGIN_SUPPRESS_IPH
errno = 0;
+#ifdef MS_WINDOWS
+ ret = _chsize_s(fd, pos);
+#else
ret = ftruncate(fd, pos);
+#endif
+ _Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS
-#endif /* !MS_WINDOWS */
-
if (ret != 0) {
Py_DECREF(posobj);
PyErr_SetFromErrno(PyExc_IOError);
@@ -1057,26 +1064,40 @@ fileio_repr(fileio *self)
PyErr_Clear();
else
return NULL;
- res = PyUnicode_FromFormat("<_io.FileIO fd=%d mode='%s'>",
- self->fd, mode_string(self));
+ res = PyUnicode_FromFormat(
+ "<_io.FileIO fd=%d mode='%s' closefd=%s>",
+ self->fd, mode_string(self), self->closefd ? "True" : "False");
}
else {
- res = PyUnicode_FromFormat("<_io.FileIO name=%R mode='%s'>",
- nameobj, mode_string(self));
+ res = PyUnicode_FromFormat(
+ "<_io.FileIO name=%R mode='%s' closefd=%s>",
+ nameobj, mode_string(self), self->closefd ? "True" : "False");
Py_DECREF(nameobj);
}
return res;
}
+/*[clinic input]
+_io.FileIO.isatty
+
+True if the file is connected to a TTY device.
+[clinic start generated code]*/
+
static PyObject *
-fileio_isatty(fileio *self)
+_io_FileIO_isatty_impl(fileio *self)
+/*[clinic end generated code: output=932c39924e9a8070 input=cd94ca1f5e95e843]*/
{
long res;
if (self->fd < 0)
return err_closed();
Py_BEGIN_ALLOW_THREADS
- res = isatty(self->fd);
+ _Py_BEGIN_SUPPRESS_IPH
+ if (_PyVerify_fd(self->fd))
+ res = isatty(self->fd);
+ else
+ res = 0;
+ _Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS
return PyBool_FromLong(res);
}
@@ -1089,110 +1110,22 @@ fileio_getstate(fileio *self)
return NULL;
}
-
-PyDoc_STRVAR(fileio_doc,
-"file(name: str[, mode: str][, opener: None]) -> file IO object\n"
-"\n"
-"Open a file. The mode can be 'r' (default), 'w', 'x' or 'a' for reading,\n"
-"writing, exclusive creation or appending. The file will be created if it\n"
-"doesn't exist when opened for writing or appending; it will be truncated\n"
-"when opened for writing. A FileExistsError will be raised if it already\n"
-"exists when opened for creating. Opening a file for creating implies\n"
-"writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode\n"
-"to allow simultaneous reading and writing. A custom opener can be used by\n"
-"passing a callable as *opener*. The underlying file descriptor for the file\n"
-"object is then obtained by calling opener with (*name*, *flags*).\n"
-"*opener* must return an open file descriptor (passing os.open as *opener*\n"
-"results in functionality similar to passing None).");
-
-PyDoc_STRVAR(read_doc,
-"read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"
-"\n"
-"Only makes one system call, so less data may be returned than requested\n"
-"In non-blocking mode, returns None if no data is available.\n"
-"Return an empty bytes object at EOF.");
-
-PyDoc_STRVAR(readall_doc,
-"readall() -> bytes. read all data from the file, returned as bytes.\n"
-"\n"
-"In non-blocking mode, returns as much as is immediately available,\n"
-"or None if no data is available. Return an empty bytes object at EOF.");
-
-PyDoc_STRVAR(write_doc,
-"write(b: bytes) -> int. Write bytes b to file, return number written.\n"
-"\n"
-"Only makes one system call, so not all of the data may be written.\n"
-"The number of bytes actually written is returned. In non-blocking mode,\n"
-"returns None if the write would block."
-);
-
-PyDoc_STRVAR(fileno_doc,
-"fileno() -> int. Return the underlying file descriptor (an integer).");
-
-PyDoc_STRVAR(seek_doc,
-"seek(offset: int[, whence: int]) -> int. Move to new file position and\n"
-"return the file position.\n"
-"\n"
-"Argument offset is a byte count. Optional argument whence defaults to\n"
-"SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n"
-"are SEEK_CUR or 1 (move relative to current position, positive or negative),\n"
-"and SEEK_END or 2 (move relative to end of file, usually negative, although\n"
-"many platforms allow seeking beyond the end of a file).\n"
-"\n"
-"Note that not all file objects are seekable.");
-
-#ifdef HAVE_FTRUNCATE
-PyDoc_STRVAR(truncate_doc,
-"truncate([size: int]) -> int. Truncate the file to at most size bytes\n"
-"and return the truncated size.\n"
-"\n"
-"Size defaults to the current file position, as returned by tell().\n"
-"The current file position is changed to the value of size.");
-#endif
-
-PyDoc_STRVAR(tell_doc,
-"tell() -> int. Current file position.\n"
-"\n"
-"Can raise OSError for non seekable files."
-);
-
-PyDoc_STRVAR(readinto_doc,
-"readinto() -> Same as RawIOBase.readinto().");
-
-PyDoc_STRVAR(close_doc,
-"close() -> None. Close the file.\n"
-"\n"
-"A closed file cannot be used for further I/O operations. close() may be\n"
-"called more than once without error.");
-
-PyDoc_STRVAR(isatty_doc,
-"isatty() -> bool. True if the file is connected to a TTY device.");
-
-PyDoc_STRVAR(seekable_doc,
-"seekable() -> bool. True if file supports random-access.");
-
-PyDoc_STRVAR(readable_doc,
-"readable() -> bool. True if file was opened in a read mode.");
-
-PyDoc_STRVAR(writable_doc,
-"writable() -> bool. True if file was opened in a write mode.");
+#include "clinic/fileio.c.h"
static PyMethodDef fileio_methods[] = {
- {"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc},
- {"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc},
- {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},
- {"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc},
- {"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc},
- {"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc},
-#ifdef HAVE_FTRUNCATE
- {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},
-#endif
- {"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc},
- {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc},
- {"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc},
- {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc},
- {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc},
- {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc},
+ _IO_FILEIO_READ_METHODDEF
+ _IO_FILEIO_READALL_METHODDEF
+ _IO_FILEIO_READINTO_METHODDEF
+ _IO_FILEIO_WRITE_METHODDEF
+ _IO_FILEIO_SEEK_METHODDEF
+ _IO_FILEIO_TELL_METHODDEF
+ _IO_FILEIO_TRUNCATE_METHODDEF
+ _IO_FILEIO_CLOSE_METHODDEF
+ _IO_FILEIO_SEEKABLE_METHODDEF
+ _IO_FILEIO_READABLE_METHODDEF
+ _IO_FILEIO_WRITABLE_METHODDEF
+ _IO_FILEIO_FILENO_METHODDEF
+ _IO_FILEIO_ISATTY_METHODDEF
{"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL},
{"__getstate__", (PyCFunction)fileio_getstate, METH_NOARGS, NULL},
{NULL, NULL} /* sentinel */
@@ -1227,6 +1160,7 @@ static PyGetSetDef fileio_getsetlist[] = {
};
static PyMemberDef fileio_members[] = {
+ {"_blksize", T_UINT, offsetof(fileio, blksize), 0},
{"_finalizing", T_BOOL, offsetof(fileio, finalizing), 0},
{NULL}
};
@@ -1253,7 +1187,7 @@ PyTypeObject PyFileIO_Type = {
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
| Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
- fileio_doc, /* tp_doc */
+ _io_FileIO___init____doc__, /* tp_doc */
(traverseproc)fileio_traverse, /* tp_traverse */
(inquiry)fileio_clear, /* tp_clear */
0, /* tp_richcompare */
@@ -1268,7 +1202,7 @@ PyTypeObject PyFileIO_Type = {
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(fileio, dict), /* tp_dictoffset */
- fileio_init, /* tp_init */
+ _io_FileIO___init__, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
fileio_new, /* tp_new */
PyObject_GC_Del, /* tp_free */