blob: 0678ef8e35409171fabf3e48d7e6c4ec86d0625f [file] [log] [blame]
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001/* Author: Daniel Stutzbach */
2
3#define PY_SSIZE_T_CLEAN
4#include "Python.h"
Andrew M. Kuchling4b81bc72010-02-22 23:12:00 +00005#ifdef HAVE_SYS_TYPES_H
Christian Heimes7f39c9f2008-01-25 12:18:43 +00006#include <sys/types.h>
Andrew M. Kuchling4b81bc72010-02-22 23:12:00 +00007#endif
8#ifdef HAVE_SYS_STAT_H
Christian Heimes7f39c9f2008-01-25 12:18:43 +00009#include <sys/stat.h>
Andrew M. Kuchling4b81bc72010-02-22 23:12:00 +000010#endif
11#ifdef HAVE_FCNTL_H
Christian Heimes7f39c9f2008-01-25 12:18:43 +000012#include <fcntl.h>
Andrew M. Kuchling4b81bc72010-02-22 23:12:00 +000013#endif
Christian Heimes7f39c9f2008-01-25 12:18:43 +000014#include <stddef.h> /* For offsetof */
Antoine Pitrou19690592009-06-12 20:14:08 +000015#include "_iomodule.h"
Christian Heimes7f39c9f2008-01-25 12:18:43 +000016
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
Antoine Pitrou19690592009-06-12 20:14:08 +000037#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
Christian Heimes7f39c9f2008-01-25 12:18:43 +000045typedef struct {
Antoine Pitroub26dc462010-05-05 16:27:30 +000046 PyObject_HEAD
47 int fd;
48 unsigned int readable : 1;
49 unsigned int writable : 1;
Antoine Pitrou213fec42013-09-04 20:46:33 +020050 unsigned int appending : 1;
Antoine Pitroub26dc462010-05-05 16:27:30 +000051 signed int seekable : 2; /* -1 means unknown */
52 unsigned int closefd : 1;
53 PyObject *weakreflist;
54 PyObject *dict;
Antoine Pitrou19690592009-06-12 20:14:08 +000055} fileio;
Christian Heimes7f39c9f2008-01-25 12:18:43 +000056
57PyTypeObject PyFileIO_Type;
58
59#define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
60
Antoine Pitrou19690592009-06-12 20:14:08 +000061int
62_PyFileIO_closed(PyObject *self)
63{
Antoine Pitroub26dc462010-05-05 16:27:30 +000064 return ((fileio *)self)->fd < 0;
Antoine Pitrou19690592009-06-12 20:14:08 +000065}
66
Antoine Pitroue741cc62009-01-21 00:45:36 +000067static PyObject *
68portable_lseek(int fd, PyObject *posobj, int whence);
69
Antoine Pitrou19690592009-06-12 20:14:08 +000070static PyObject *portable_lseek(int fd, PyObject *posobj, int whence);
71
72/* Returns 0 on success, -1 with exception set on failure. */
Christian Heimes7f39c9f2008-01-25 12:18:43 +000073static int
Antoine Pitrou19690592009-06-12 20:14:08 +000074internal_close(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +000075{
Antoine Pitroub26dc462010-05-05 16:27:30 +000076 int err = 0;
77 int save_errno = 0;
78 if (self->fd >= 0) {
79 int fd = self->fd;
80 self->fd = -1;
81 /* fd is accessible and someone else may have closed it */
82 if (_PyVerify_fd(fd)) {
83 Py_BEGIN_ALLOW_THREADS
84 err = close(fd);
85 if (err < 0)
86 save_errno = errno;
87 Py_END_ALLOW_THREADS
88 } else {
89 save_errno = errno;
90 err = -1;
91 }
92 }
93 if (err < 0) {
94 errno = save_errno;
95 PyErr_SetFromErrno(PyExc_IOError);
96 return -1;
97 }
98 return 0;
Christian Heimes7f39c9f2008-01-25 12:18:43 +000099}
100
101static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000102fileio_close(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000103{
Serhiy Storchaka3173f7c2015-02-21 00:34:20 +0200104 PyObject *res;
105 res = PyObject_CallMethod((PyObject*)&PyRawIOBase_Type,
106 "close", "O", self);
Antoine Pitroub26dc462010-05-05 16:27:30 +0000107 if (!self->closefd) {
108 self->fd = -1;
Serhiy Storchaka3173f7c2015-02-21 00:34:20 +0200109 return res;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000110 }
Serhiy Storchaka3173f7c2015-02-21 00:34:20 +0200111 if (internal_close(self) < 0)
112 Py_CLEAR(res);
113 return res;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000114}
115
116static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000117fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000118{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000119 fileio *self;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000120
Antoine Pitroub26dc462010-05-05 16:27:30 +0000121 assert(type != NULL && type->tp_alloc != NULL);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000122
Antoine Pitroub26dc462010-05-05 16:27:30 +0000123 self = (fileio *) type->tp_alloc(type, 0);
124 if (self != NULL) {
125 self->fd = -1;
126 self->readable = 0;
127 self->writable = 0;
Antoine Pitrou213fec42013-09-04 20:46:33 +0200128 self->appending = 0;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000129 self->seekable = -1;
130 self->closefd = 1;
131 self->weakreflist = NULL;
132 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000133
Antoine Pitroub26dc462010-05-05 16:27:30 +0000134 return (PyObject *) self;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000135}
136
137/* On Unix, open will succeed for directories.
138 In Python, there should be no file objects referring to
139 directories, so we need a check. */
140
141static int
Antoine Pitrouc2ec9922012-07-06 18:48:24 +0200142dircheck(fileio* self, PyObject *nameobj)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000143{
144#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000145 struct stat buf;
146 if (self->fd < 0)
147 return 0;
148 if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
Antoine Pitrouc2ec9922012-07-06 18:48:24 +0200149 errno = EISDIR;
150 PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj);
Antoine Pitroub26dc462010-05-05 16:27:30 +0000151 return -1;
152 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000153#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000154 return 0;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000155}
156
Benjamin Peterson5848d1f2009-01-19 00:08:08 +0000157static int
158check_fd(int fd)
159{
160#if defined(HAVE_FSTAT)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000161 struct stat buf;
162 if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) {
163 PyObject *exc;
164 char *msg = strerror(EBADF);
165 exc = PyObject_CallFunction(PyExc_OSError, "(is)",
166 EBADF, msg);
167 PyErr_SetObject(PyExc_OSError, exc);
168 Py_XDECREF(exc);
169 return -1;
170 }
Benjamin Peterson5848d1f2009-01-19 00:08:08 +0000171#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000172 return 0;
Benjamin Peterson5848d1f2009-01-19 00:08:08 +0000173}
174
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000175
176static int
177fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
178{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000179 fileio *self = (fileio *) oself;
180 static char *kwlist[] = {"file", "mode", "closefd", NULL};
181 const char *name = NULL;
182 PyObject *nameobj, *stringobj = NULL;
183 char *mode = "r";
184 char *s;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000185#ifdef MS_WINDOWS
Antoine Pitroub26dc462010-05-05 16:27:30 +0000186 Py_UNICODE *widename = NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000187#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000188 int ret = 0;
Antoine Pitrou213fec42013-09-04 20:46:33 +0200189 int rwa = 0, plus = 0;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000190 int flags = 0;
191 int fd = -1;
192 int closefd = 1;
Hynek Schlawack9bd4bf22012-06-21 19:45:19 +0200193 int fd_is_own = 0;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000194
Antoine Pitroub26dc462010-05-05 16:27:30 +0000195 assert(PyFileIO_Check(oself));
196 if (self->fd >= 0) {
Hynek Schlawack877effc2012-05-25 09:24:18 +0200197 if (self->closefd) {
198 /* Have to close the existing file first. */
199 if (internal_close(self) < 0)
200 return -1;
201 }
202 else
203 self->fd = -1;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000204 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000205
Antoine Pitroub26dc462010-05-05 16:27:30 +0000206 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:fileio",
207 kwlist, &nameobj, &mode, &closefd))
208 return -1;
Antoine Pitrou19690592009-06-12 20:14:08 +0000209
Antoine Pitroub26dc462010-05-05 16:27:30 +0000210 if (PyFloat_Check(nameobj)) {
211 PyErr_SetString(PyExc_TypeError,
212 "integer argument expected, got float");
213 return -1;
214 }
Antoine Pitrou19690592009-06-12 20:14:08 +0000215
Serhiy Storchaka74f49ab2013-01-19 12:55:39 +0200216 fd = _PyLong_AsInt(nameobj);
Antoine Pitroub26dc462010-05-05 16:27:30 +0000217 if (fd < 0) {
218 if (!PyErr_Occurred()) {
219 PyErr_SetString(PyExc_ValueError,
Serhiy Storchaka46129542015-04-10 16:08:33 +0300220 "negative file descriptor");
Antoine Pitroub26dc462010-05-05 16:27:30 +0000221 return -1;
222 }
223 PyErr_Clear();
224 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000225
Hirokazu Yamamotob24bb272009-05-17 02:52:09 +0000226#ifdef MS_WINDOWS
Serhiy Storchaka3c9ce742016-07-01 23:34:44 +0300227 if (PyUnicode_Check(nameobj)) {
Antoine Pitroub26dc462010-05-05 16:27:30 +0000228 widename = PyUnicode_AS_UNICODE(nameobj);
Serhiy Storchaka3c9ce742016-07-01 23:34:44 +0300229 if (wcslen(widename) != (size_t)PyUnicode_GET_SIZE(nameobj)) {
230 PyErr_SetString(PyExc_TypeError, "embedded NUL character");
231 return -1;
232 }
233 }
Antoine Pitroub26dc462010-05-05 16:27:30 +0000234 if (widename == NULL)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000235#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000236 if (fd < 0)
237 {
238 if (PyBytes_Check(nameobj) || PyByteArray_Check(nameobj)) {
239 Py_ssize_t namelen;
240 if (PyObject_AsCharBuffer(nameobj, &name, &namelen) < 0)
241 return -1;
Serhiy Storchaka3c9ce742016-07-01 23:34:44 +0300242 if (strlen(name) != (size_t)namelen) {
243 PyErr_SetString(PyExc_TypeError, "embedded NUL character");
244 return -1;
245 }
Antoine Pitroub26dc462010-05-05 16:27:30 +0000246 }
247 else {
248 PyObject *u = PyUnicode_FromObject(nameobj);
Antoine Pitrou19690592009-06-12 20:14:08 +0000249
Antoine Pitroub26dc462010-05-05 16:27:30 +0000250 if (u == NULL)
251 return -1;
Antoine Pitrou19690592009-06-12 20:14:08 +0000252
Antoine Pitroub26dc462010-05-05 16:27:30 +0000253 stringobj = PyUnicode_AsEncodedString(
254 u, Py_FileSystemDefaultEncoding, NULL);
255 Py_DECREF(u);
256 if (stringobj == NULL)
257 return -1;
258 if (!PyBytes_Check(stringobj)) {
259 PyErr_SetString(PyExc_TypeError,
260 "encoder failed to return bytes");
261 goto error;
262 }
263 name = PyBytes_AS_STRING(stringobj);
Serhiy Storchaka3c9ce742016-07-01 23:34:44 +0300264 if (strlen(name) != (size_t)PyBytes_GET_SIZE(stringobj)) {
265 PyErr_SetString(PyExc_TypeError, "embedded NUL character");
266 goto error;
267 }
Antoine Pitroub26dc462010-05-05 16:27:30 +0000268 }
269 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000270
Antoine Pitroub26dc462010-05-05 16:27:30 +0000271 s = mode;
272 while (*s) {
273 switch (*s++) {
274 case 'r':
275 if (rwa) {
276 bad_mode:
277 PyErr_SetString(PyExc_ValueError,
Georg Brandl10603802010-11-26 08:10:41 +0000278 "Must have exactly one of read/write/append "
279 "mode and at most one plus");
Antoine Pitroub26dc462010-05-05 16:27:30 +0000280 goto error;
281 }
282 rwa = 1;
283 self->readable = 1;
284 break;
285 case 'w':
286 if (rwa)
287 goto bad_mode;
288 rwa = 1;
289 self->writable = 1;
290 flags |= O_CREAT | O_TRUNC;
291 break;
292 case 'a':
293 if (rwa)
294 goto bad_mode;
295 rwa = 1;
296 self->writable = 1;
Antoine Pitrou213fec42013-09-04 20:46:33 +0200297 self->appending = 1;
298 flags |= O_APPEND | O_CREAT;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000299 break;
300 case 'b':
301 break;
302 case '+':
303 if (plus)
304 goto bad_mode;
305 self->readable = self->writable = 1;
306 plus = 1;
307 break;
308 default:
309 PyErr_Format(PyExc_ValueError,
310 "invalid mode: %.200s", mode);
311 goto error;
312 }
313 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000314
Antoine Pitroub26dc462010-05-05 16:27:30 +0000315 if (!rwa)
316 goto bad_mode;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000317
Antoine Pitroub26dc462010-05-05 16:27:30 +0000318 if (self->readable && self->writable)
319 flags |= O_RDWR;
320 else if (self->readable)
321 flags |= O_RDONLY;
322 else
323 flags |= O_WRONLY;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000324
325#ifdef O_BINARY
Antoine Pitroub26dc462010-05-05 16:27:30 +0000326 flags |= O_BINARY;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000327#endif
328
Antoine Pitroub26dc462010-05-05 16:27:30 +0000329 if (fd >= 0) {
330 if (check_fd(fd))
331 goto error;
332 self->fd = fd;
333 self->closefd = closefd;
334 }
335 else {
336 self->closefd = 1;
337 if (!closefd) {
338 PyErr_SetString(PyExc_ValueError,
339 "Cannot use closefd=False with file name");
340 goto error;
341 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000342
Antoine Pitroub26dc462010-05-05 16:27:30 +0000343 Py_BEGIN_ALLOW_THREADS
344 errno = 0;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000345#ifdef MS_WINDOWS
Antoine Pitroub26dc462010-05-05 16:27:30 +0000346 if (widename != NULL)
347 self->fd = _wopen(widename, flags, 0666);
348 else
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000349#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000350 self->fd = open(name, flags, 0666);
351 Py_END_ALLOW_THREADS
Hynek Schlawack9bd4bf22012-06-21 19:45:19 +0200352 fd_is_own = 1;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000353 if (self->fd < 0) {
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000354#ifdef MS_WINDOWS
Antoine Pitroub26dc462010-05-05 16:27:30 +0000355 if (widename != NULL)
356 PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename);
357 else
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000358#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000359 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
360 goto error;
361 }
Antoine Pitroub26dc462010-05-05 16:27:30 +0000362 }
Antoine Pitrouc2ec9922012-07-06 18:48:24 +0200363 if (dircheck(self, nameobj) < 0)
364 goto error;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000365
Antoine Pitroub26dc462010-05-05 16:27:30 +0000366 if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0)
367 goto error;
Antoine Pitrou19690592009-06-12 20:14:08 +0000368
Antoine Pitrou213fec42013-09-04 20:46:33 +0200369 if (self->appending) {
Antoine Pitroub26dc462010-05-05 16:27:30 +0000370 /* For consistent behaviour, we explicitly seek to the
371 end of file (otherwise, it might be done only on the
372 first write()). */
373 PyObject *pos = portable_lseek(self->fd, NULL, 2);
Hynek Schlawack9bd4bf22012-06-21 19:45:19 +0200374 if (pos == NULL)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000375 goto error;
376 Py_DECREF(pos);
377 }
Antoine Pitroue741cc62009-01-21 00:45:36 +0000378
Antoine Pitroub26dc462010-05-05 16:27:30 +0000379 goto done;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000380
381 error:
Hynek Schlawack9bd4bf22012-06-21 19:45:19 +0200382 if (!fd_is_own)
383 self->fd = -1;
384
Antoine Pitroub26dc462010-05-05 16:27:30 +0000385 ret = -1;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000386
387 done:
Antoine Pitroub26dc462010-05-05 16:27:30 +0000388 Py_CLEAR(stringobj);
389 return ret;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000390}
391
Antoine Pitrou19690592009-06-12 20:14:08 +0000392static int
393fileio_traverse(fileio *self, visitproc visit, void *arg)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000394{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000395 Py_VISIT(self->dict);
396 return 0;
Antoine Pitrou19690592009-06-12 20:14:08 +0000397}
398
399static int
400fileio_clear(fileio *self)
401{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000402 Py_CLEAR(self->dict);
403 return 0;
Antoine Pitrou19690592009-06-12 20:14:08 +0000404}
405
406static void
407fileio_dealloc(fileio *self)
408{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000409 if (_PyIOBase_finalize((PyObject *) self) < 0)
410 return;
411 _PyObject_GC_UNTRACK(self);
412 if (self->weakreflist != NULL)
413 PyObject_ClearWeakRefs((PyObject *) self);
414 Py_CLEAR(self->dict);
415 Py_TYPE(self)->tp_free((PyObject *)self);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000416}
417
418static PyObject *
419err_closed(void)
420{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000421 PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
422 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000423}
424
425static PyObject *
426err_mode(char *action)
427{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000428 PyErr_Format(PyExc_ValueError, "File not open for %s", action);
429 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000430}
431
432static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000433fileio_fileno(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000434{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000435 if (self->fd < 0)
436 return err_closed();
437 return PyInt_FromLong((long) self->fd);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000438}
439
440static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000441fileio_readable(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000442{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000443 if (self->fd < 0)
444 return err_closed();
445 return PyBool_FromLong((long) self->readable);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000446}
447
448static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000449fileio_writable(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000450{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000451 if (self->fd < 0)
452 return err_closed();
453 return PyBool_FromLong((long) self->writable);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000454}
455
456static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000457fileio_seekable(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000458{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000459 if (self->fd < 0)
460 return err_closed();
461 if (self->seekable < 0) {
462 PyObject *pos = portable_lseek(self->fd, NULL, SEEK_CUR);
463 if (pos == NULL) {
464 PyErr_Clear();
465 self->seekable = 0;
466 } else {
467 Py_DECREF(pos);
468 self->seekable = 1;
469 }
470 }
471 return PyBool_FromLong((long) self->seekable);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000472}
473
474static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000475fileio_readinto(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000476{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000477 Py_buffer pbuf;
Victor Stinner59729ff2011-07-05 11:28:19 +0200478 Py_ssize_t n, len;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000479
Antoine Pitroub26dc462010-05-05 16:27:30 +0000480 if (self->fd < 0)
481 return err_closed();
482 if (!self->readable)
483 return err_mode("reading");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000484
Antoine Pitroub26dc462010-05-05 16:27:30 +0000485 if (!PyArg_ParseTuple(args, "w*", &pbuf))
486 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000487
Antoine Pitroub26dc462010-05-05 16:27:30 +0000488 if (_PyVerify_fd(self->fd)) {
Victor Stinner59729ff2011-07-05 11:28:19 +0200489 len = pbuf.len;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000490 Py_BEGIN_ALLOW_THREADS
491 errno = 0;
Victor Stinner59729ff2011-07-05 11:28:19 +0200492#if defined(MS_WIN64) || defined(MS_WINDOWS)
493 if (len > INT_MAX)
494 len = INT_MAX;
495 n = read(self->fd, pbuf.buf, (int)len);
496#else
497 n = read(self->fd, pbuf.buf, len);
498#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000499 Py_END_ALLOW_THREADS
500 } else
501 n = -1;
502 PyBuffer_Release(&pbuf);
503 if (n < 0) {
504 if (errno == EAGAIN)
505 Py_RETURN_NONE;
506 PyErr_SetFromErrno(PyExc_IOError);
507 return NULL;
508 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000509
Antoine Pitroub26dc462010-05-05 16:27:30 +0000510 return PyLong_FromSsize_t(n);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000511}
512
Antoine Pitrou19690592009-06-12 20:14:08 +0000513static size_t
514new_buffersize(fileio *self, size_t currentsize)
515{
516#ifdef HAVE_FSTAT
Antoine Pitroub26dc462010-05-05 16:27:30 +0000517 off_t pos, end;
518 struct stat st;
519 if (fstat(self->fd, &st) == 0) {
520 end = st.st_size;
521 pos = lseek(self->fd, 0L, SEEK_CUR);
522 /* Files claiming a size smaller than SMALLCHUNK may
523 actually be streaming pseudo-files. In this case, we
524 apply the more aggressive algorithm below.
525 */
526 if (end >= SMALLCHUNK && end >= pos && pos >= 0) {
527 /* Add 1 so if the file were to grow we'd notice. */
528 return currentsize + end - pos + 1;
529 }
530 }
Antoine Pitrou19690592009-06-12 20:14:08 +0000531#endif
Nadeem Vawda36248152011-10-13 13:52:46 +0200532 /* Expand the buffer by an amount proportional to the current size,
533 giving us amortized linear-time behavior. Use a less-than-double
534 growth factor to avoid excessive allocation. */
535 return currentsize + (currentsize >> 3) + 6;
Antoine Pitrou19690592009-06-12 20:14:08 +0000536}
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000537
538static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000539fileio_readall(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000540{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000541 PyObject *result;
542 Py_ssize_t total = 0;
Victor Stinner23a32ba2013-01-03 03:33:21 +0100543 Py_ssize_t n;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000544
Victor Stinner5100a402011-05-25 22:15:36 +0200545 if (self->fd < 0)
546 return err_closed();
Antoine Pitroub26dc462010-05-05 16:27:30 +0000547 if (!_PyVerify_fd(self->fd))
548 return PyErr_SetFromErrno(PyExc_IOError);
Antoine Pitrou19690592009-06-12 20:14:08 +0000549
Antoine Pitroub26dc462010-05-05 16:27:30 +0000550 result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
551 if (result == NULL)
552 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000553
Antoine Pitroub26dc462010-05-05 16:27:30 +0000554 while (1) {
555 size_t newsize = new_buffersize(self, total);
556 if (newsize > PY_SSIZE_T_MAX || newsize <= 0) {
557 PyErr_SetString(PyExc_OverflowError,
558 "unbounded read returned more bytes "
559 "than a Python string can hold ");
560 Py_DECREF(result);
561 return NULL;
562 }
Antoine Pitrou19690592009-06-12 20:14:08 +0000563
Antoine Pitroub26dc462010-05-05 16:27:30 +0000564 if (PyBytes_GET_SIZE(result) < (Py_ssize_t)newsize) {
Kristján Valur Jónssonbe580f22014-04-25 09:51:21 +0000565 if (_PyBytes_Resize(&result, newsize) < 0)
566 return NULL; /* result has been freed */
Antoine Pitroub26dc462010-05-05 16:27:30 +0000567 }
568 Py_BEGIN_ALLOW_THREADS
569 errno = 0;
Victor Stinner23a32ba2013-01-03 03:33:21 +0100570 n = newsize - total;
571#if defined(MS_WIN64) || defined(MS_WINDOWS)
572 if (n > INT_MAX)
573 n = INT_MAX;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000574 n = read(self->fd,
575 PyBytes_AS_STRING(result) + total,
Victor Stinner23a32ba2013-01-03 03:33:21 +0100576 (int)n);
577#else
578 n = read(self->fd,
579 PyBytes_AS_STRING(result) + total,
580 n);
581#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000582 Py_END_ALLOW_THREADS
583 if (n == 0)
584 break;
585 if (n < 0) {
Gregory P. Smith99716162012-10-12 13:02:06 -0700586 if (errno == EINTR) {
587 if (PyErr_CheckSignals()) {
588 Py_DECREF(result);
589 return NULL;
590 }
591 continue;
592 }
Antoine Pitroub26dc462010-05-05 16:27:30 +0000593 if (errno == EAGAIN) {
Victor Stinnerf6b3c842014-07-02 23:12:48 +0200594 if (total > 0)
595 break;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000596 Py_DECREF(result);
597 Py_RETURN_NONE;
598 }
599 Py_DECREF(result);
600 PyErr_SetFromErrno(PyExc_IOError);
601 return NULL;
602 }
603 total += n;
604 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000605
Antoine Pitroub26dc462010-05-05 16:27:30 +0000606 if (PyBytes_GET_SIZE(result) > total) {
607 if (_PyBytes_Resize(&result, total) < 0) {
608 /* This should never happen, but just in case */
Antoine Pitroub26dc462010-05-05 16:27:30 +0000609 return NULL;
610 }
611 }
612 return result;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000613}
614
615static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000616fileio_read(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000617{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000618 char *ptr;
619 Py_ssize_t n;
620 Py_ssize_t size = -1;
621 PyObject *bytes;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000622
Antoine Pitroub26dc462010-05-05 16:27:30 +0000623 if (self->fd < 0)
624 return err_closed();
625 if (!self->readable)
626 return err_mode("reading");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000627
Antoine Pitroub26dc462010-05-05 16:27:30 +0000628 if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size))
629 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000630
Antoine Pitroub26dc462010-05-05 16:27:30 +0000631 if (size < 0) {
632 return fileio_readall(self);
633 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000634
Victor Stinner59729ff2011-07-05 11:28:19 +0200635#if defined(MS_WIN64) || defined(MS_WINDOWS)
636 if (size > INT_MAX)
637 size = INT_MAX;
638#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000639 bytes = PyBytes_FromStringAndSize(NULL, size);
640 if (bytes == NULL)
641 return NULL;
642 ptr = PyBytes_AS_STRING(bytes);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000643
Antoine Pitroub26dc462010-05-05 16:27:30 +0000644 if (_PyVerify_fd(self->fd)) {
645 Py_BEGIN_ALLOW_THREADS
646 errno = 0;
Victor Stinner59729ff2011-07-05 11:28:19 +0200647#if defined(MS_WIN64) || defined(MS_WINDOWS)
648 n = read(self->fd, ptr, (int)size);
649#else
Antoine Pitroub26dc462010-05-05 16:27:30 +0000650 n = read(self->fd, ptr, size);
Victor Stinner59729ff2011-07-05 11:28:19 +0200651#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000652 Py_END_ALLOW_THREADS
653 } else
654 n = -1;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000655
Antoine Pitroub26dc462010-05-05 16:27:30 +0000656 if (n < 0) {
657 Py_DECREF(bytes);
658 if (errno == EAGAIN)
659 Py_RETURN_NONE;
660 PyErr_SetFromErrno(PyExc_IOError);
661 return NULL;
662 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000663
Antoine Pitroub26dc462010-05-05 16:27:30 +0000664 if (n != size) {
Kristján Valur Jónssonbe580f22014-04-25 09:51:21 +0000665 if (_PyBytes_Resize(&bytes, n) < 0)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000666 return NULL;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000667 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000668
Antoine Pitroub26dc462010-05-05 16:27:30 +0000669 return (PyObject *) bytes;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000670}
671
672static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000673fileio_write(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000674{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000675 Py_buffer pbuf;
Victor Stinner59729ff2011-07-05 11:28:19 +0200676 Py_ssize_t n, len;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000677
Antoine Pitroub26dc462010-05-05 16:27:30 +0000678 if (self->fd < 0)
679 return err_closed();
680 if (!self->writable)
681 return err_mode("writing");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000682
Antoine Pitroub26dc462010-05-05 16:27:30 +0000683 if (!PyArg_ParseTuple(args, "s*", &pbuf))
684 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000685
Antoine Pitroub26dc462010-05-05 16:27:30 +0000686 if (_PyVerify_fd(self->fd)) {
687 Py_BEGIN_ALLOW_THREADS
688 errno = 0;
Victor Stinner59729ff2011-07-05 11:28:19 +0200689 len = pbuf.len;
690#if defined(MS_WIN64) || defined(MS_WINDOWS)
691 if (len > INT_MAX)
692 len = INT_MAX;
693 n = write(self->fd, pbuf.buf, (int)len);
694#else
695 n = write(self->fd, pbuf.buf, len);
696#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000697 Py_END_ALLOW_THREADS
698 } else
699 n = -1;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000700
Antoine Pitroub26dc462010-05-05 16:27:30 +0000701 PyBuffer_Release(&pbuf);
Martin v. Löwisf91d46a2008-08-12 14:49:50 +0000702
Antoine Pitroub26dc462010-05-05 16:27:30 +0000703 if (n < 0) {
704 if (errno == EAGAIN)
705 Py_RETURN_NONE;
706 PyErr_SetFromErrno(PyExc_IOError);
707 return NULL;
708 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000709
Antoine Pitroub26dc462010-05-05 16:27:30 +0000710 return PyLong_FromSsize_t(n);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000711}
712
713/* XXX Windows support below is likely incomplete */
714
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000715/* Cribbed from posix_lseek() */
716static PyObject *
717portable_lseek(int fd, PyObject *posobj, int whence)
718{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000719 Py_off_t pos, res;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000720
721#ifdef SEEK_SET
Antoine Pitroub26dc462010-05-05 16:27:30 +0000722 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
723 switch (whence) {
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000724#if SEEK_SET != 0
Antoine Pitroub26dc462010-05-05 16:27:30 +0000725 case 0: whence = SEEK_SET; break;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000726#endif
727#if SEEK_CUR != 1
Antoine Pitroub26dc462010-05-05 16:27:30 +0000728 case 1: whence = SEEK_CUR; break;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000729#endif
Benjamin Peterson8024cec2009-01-20 14:31:08 +0000730#if SEEK_END != 2
Antoine Pitroub26dc462010-05-05 16:27:30 +0000731 case 2: whence = SEEK_END; break;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000732#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000733 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000734#endif /* SEEK_SET */
735
Antoine Pitroub26dc462010-05-05 16:27:30 +0000736 if (posobj == NULL)
737 pos = 0;
738 else {
739 if(PyFloat_Check(posobj)) {
740 PyErr_SetString(PyExc_TypeError, "an integer is required");
741 return NULL;
742 }
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000743#if defined(HAVE_LARGEFILE_SUPPORT)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000744 pos = PyLong_AsLongLong(posobj);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000745#else
Antoine Pitroub26dc462010-05-05 16:27:30 +0000746 pos = PyLong_AsLong(posobj);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000747#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000748 if (PyErr_Occurred())
749 return NULL;
750 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000751
Antoine Pitroub26dc462010-05-05 16:27:30 +0000752 if (_PyVerify_fd(fd)) {
753 Py_BEGIN_ALLOW_THREADS
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000754#if defined(MS_WIN64) || defined(MS_WINDOWS)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000755 res = _lseeki64(fd, pos, whence);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000756#else
Antoine Pitroub26dc462010-05-05 16:27:30 +0000757 res = lseek(fd, pos, whence);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000758#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000759 Py_END_ALLOW_THREADS
760 } else
761 res = -1;
762 if (res < 0)
763 return PyErr_SetFromErrno(PyExc_IOError);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000764
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000765#if defined(HAVE_LARGEFILE_SUPPORT)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000766 return PyLong_FromLongLong(res);
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000767#else
Antoine Pitroub26dc462010-05-05 16:27:30 +0000768 return PyLong_FromLong(res);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000769#endif
770}
771
772static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000773fileio_seek(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000774{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000775 PyObject *posobj;
776 int whence = 0;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000777
Antoine Pitroub26dc462010-05-05 16:27:30 +0000778 if (self->fd < 0)
779 return err_closed();
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000780
Antoine Pitroub26dc462010-05-05 16:27:30 +0000781 if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))
782 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000783
Antoine Pitroub26dc462010-05-05 16:27:30 +0000784 return portable_lseek(self->fd, posobj, whence);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000785}
786
787static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000788fileio_tell(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000789{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000790 if (self->fd < 0)
791 return err_closed();
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000792
Antoine Pitroub26dc462010-05-05 16:27:30 +0000793 return portable_lseek(self->fd, NULL, 1);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000794}
795
796#ifdef HAVE_FTRUNCATE
797static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000798fileio_truncate(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000799{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000800 PyObject *posobj = NULL; /* the new size wanted by the user */
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000801#ifndef MS_WINDOWS
Antoine Pitroub26dc462010-05-05 16:27:30 +0000802 Py_off_t pos;
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000803#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000804 int ret;
805 int fd;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000806
Antoine Pitroub26dc462010-05-05 16:27:30 +0000807 fd = self->fd;
808 if (fd < 0)
809 return err_closed();
810 if (!self->writable)
811 return err_mode("writing");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000812
Antoine Pitroub26dc462010-05-05 16:27:30 +0000813 if (!PyArg_ParseTuple(args, "|O", &posobj))
814 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000815
Antoine Pitroub26dc462010-05-05 16:27:30 +0000816 if (posobj == Py_None || posobj == NULL) {
817 /* Get the current position. */
818 posobj = portable_lseek(fd, NULL, 1);
819 if (posobj == NULL)
820 return NULL;
821 }
822 else {
823 Py_INCREF(posobj);
824 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000825
826#ifdef MS_WINDOWS
Antoine Pitroub26dc462010-05-05 16:27:30 +0000827 /* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
828 so don't even try using it. */
829 {
830 PyObject *oldposobj, *tempposobj;
831 HANDLE hFile;
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000832
Antoine Pitroub26dc462010-05-05 16:27:30 +0000833 /* we save the file pointer position */
834 oldposobj = portable_lseek(fd, NULL, 1);
835 if (oldposobj == NULL) {
836 Py_DECREF(posobj);
837 return NULL;
838 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000839
Antoine Pitroub26dc462010-05-05 16:27:30 +0000840 /* we then move to the truncation position */
841 tempposobj = portable_lseek(fd, posobj, 0);
842 if (tempposobj == NULL) {
843 Py_DECREF(oldposobj);
844 Py_DECREF(posobj);
845 return NULL;
846 }
847 Py_DECREF(tempposobj);
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000848
Antoine Pitroub26dc462010-05-05 16:27:30 +0000849 /* Truncate. Note that this may grow the file! */
850 Py_BEGIN_ALLOW_THREADS
851 errno = 0;
852 hFile = (HANDLE)_get_osfhandle(fd);
853 ret = hFile == (HANDLE)-1; /* testing for INVALID_HANDLE value */
854 if (ret == 0) {
855 ret = SetEndOfFile(hFile) == 0;
856 if (ret)
857 errno = EACCES;
858 }
859 Py_END_ALLOW_THREADS
860
861 /* we restore the file pointer position in any case */
862 tempposobj = portable_lseek(fd, oldposobj, 0);
863 Py_DECREF(oldposobj);
864 if (tempposobj == NULL) {
865 Py_DECREF(posobj);
866 return NULL;
867 }
868 Py_DECREF(tempposobj);
869 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000870#else
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000871
872#if defined(HAVE_LARGEFILE_SUPPORT)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000873 pos = PyLong_AsLongLong(posobj);
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000874#else
Antoine Pitroub26dc462010-05-05 16:27:30 +0000875 pos = PyLong_AsLong(posobj);
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000876#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000877 if (PyErr_Occurred()){
878 Py_DECREF(posobj);
879 return NULL;
880 }
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000881
Antoine Pitroub26dc462010-05-05 16:27:30 +0000882 Py_BEGIN_ALLOW_THREADS
883 errno = 0;
884 ret = ftruncate(fd, pos);
885 Py_END_ALLOW_THREADS
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000886
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000887#endif /* !MS_WINDOWS */
888
Antoine Pitroub26dc462010-05-05 16:27:30 +0000889 if (ret != 0) {
890 Py_DECREF(posobj);
891 PyErr_SetFromErrno(PyExc_IOError);
892 return NULL;
893 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000894
Antoine Pitroub26dc462010-05-05 16:27:30 +0000895 return posobj;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000896}
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000897#endif /* HAVE_FTRUNCATE */
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000898
899static char *
Antoine Pitrou19690592009-06-12 20:14:08 +0000900mode_string(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000901{
Antoine Pitrou213fec42013-09-04 20:46:33 +0200902 if (self->appending) {
903 if (self->readable)
904 return "ab+";
905 else
906 return "ab";
907 }
908 else if (self->readable) {
Antoine Pitroub26dc462010-05-05 16:27:30 +0000909 if (self->writable)
910 return "rb+";
911 else
912 return "rb";
913 }
914 else
915 return "wb";
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000916}
917
918static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000919fileio_repr(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000920{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000921 PyObject *nameobj, *res;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000922
Antoine Pitroub26dc462010-05-05 16:27:30 +0000923 if (self->fd < 0)
924 return PyString_FromFormat("<_io.FileIO [closed]>");
Antoine Pitrou19690592009-06-12 20:14:08 +0000925
Antoine Pitroub26dc462010-05-05 16:27:30 +0000926 nameobj = PyObject_GetAttrString((PyObject *) self, "name");
927 if (nameobj == NULL) {
928 if (PyErr_ExceptionMatches(PyExc_AttributeError))
929 PyErr_Clear();
930 else
931 return NULL;
932 res = PyString_FromFormat("<_io.FileIO fd=%d mode='%s'>",
933 self->fd, mode_string(self));
934 }
935 else {
936 PyObject *repr = PyObject_Repr(nameobj);
937 Py_DECREF(nameobj);
938 if (repr == NULL)
939 return NULL;
940 res = PyString_FromFormat("<_io.FileIO name=%s mode='%s'>",
941 PyString_AS_STRING(repr),
942 mode_string(self));
943 Py_DECREF(repr);
944 }
945 return res;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000946}
947
948static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000949fileio_isatty(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000950{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000951 long res;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000952
Antoine Pitroub26dc462010-05-05 16:27:30 +0000953 if (self->fd < 0)
954 return err_closed();
955 Py_BEGIN_ALLOW_THREADS
956 res = isatty(self->fd);
957 Py_END_ALLOW_THREADS
958 return PyBool_FromLong(res);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000959}
960
961
962PyDoc_STRVAR(fileio_doc,
963"file(name: str[, mode: str]) -> file IO object\n"
964"\n"
Serhiy Storchaka46129542015-04-10 16:08:33 +0300965"Open a file. The mode can be 'r' (default), 'w' or 'a' for reading,\n"
Antoine Pitroub26dc462010-05-05 16:27:30 +0000966"writing or appending. The file will be created if it doesn't exist\n"
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000967"when opened for writing or appending; it will be truncated when\n"
968"opened for writing. Add a '+' to the mode to allow simultaneous\n"
969"reading and writing.");
970
971PyDoc_STRVAR(read_doc,
972"read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"
973"\n"
974"Only makes one system call, so less data may be returned than requested\n"
975"In non-blocking mode, returns None if no data is available.\n"
976"On end-of-file, returns ''.");
977
978PyDoc_STRVAR(readall_doc,
979"readall() -> bytes. read all data from the file, returned as bytes.\n"
980"\n"
981"In non-blocking mode, returns as much as is immediately available,\n"
982"or None if no data is available. On end-of-file, returns ''.");
983
984PyDoc_STRVAR(write_doc,
Martin Panterc9813d82016-06-03 05:59:20 +0000985"write(b) -> int. Write array of bytes b, return number written.\n"
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000986"\n"
987"Only makes one system call, so not all of the data may be written.\n"
Serhiy Storchaka46129542015-04-10 16:08:33 +0300988"The number of bytes actually written is returned. In non-blocking mode,\n"
989"returns None if the write would block."
990);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000991
992PyDoc_STRVAR(fileno_doc,
Serhiy Storchaka46129542015-04-10 16:08:33 +0300993"fileno() -> int. Return the underlying file descriptor (an integer).");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000994
995PyDoc_STRVAR(seek_doc,
Berker Peksagb5dc3dc2014-09-24 12:54:25 +0300996"seek(offset: int[, whence: int]) -> int. Move to new file position\n"
997"and return the file position.\n"
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000998"\n"
999"Argument offset is a byte count. Optional argument whence defaults to\n"
Serhiy Storchaka46129542015-04-10 16:08:33 +03001000"SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n"
1001"are SEEK_CUR or 1 (move relative to current position, positive or negative),\n"
1002"and SEEK_END or 2 (move relative to end of file, usually negative, although\n"
1003"many platforms allow seeking beyond the end of a file).\n"
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001004"\n"
1005"Note that not all file objects are seekable.");
1006
1007#ifdef HAVE_FTRUNCATE
1008PyDoc_STRVAR(truncate_doc,
Berker Peksagb5dc3dc2014-09-24 12:54:25 +03001009"truncate([size: int]) -> int. Truncate the file to at most size bytes and\n"
1010"return the truncated size.\n"
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001011"\n"
Berker Peksagb5dc3dc2014-09-24 12:54:25 +03001012"Size defaults to the current file position, as returned by tell().\n"
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +00001013"The current file position is changed to the value of size.");
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001014#endif
1015
1016PyDoc_STRVAR(tell_doc,
Serhiy Storchaka46129542015-04-10 16:08:33 +03001017"tell() -> int. Current file position.\n"
1018"\n"
1019"Can raise OSError for non seekable files."
1020);
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001021
1022PyDoc_STRVAR(readinto_doc,
Antoine Pitrou19690592009-06-12 20:14:08 +00001023"readinto() -> Same as RawIOBase.readinto().");
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001024
1025PyDoc_STRVAR(close_doc,
1026"close() -> None. Close the file.\n"
1027"\n"
1028"A closed file cannot be used for further I/O operations. close() may be\n"
Serhiy Storchaka46129542015-04-10 16:08:33 +03001029"called more than once without error.");
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001030
1031PyDoc_STRVAR(isatty_doc,
Serhiy Storchaka46129542015-04-10 16:08:33 +03001032"isatty() -> bool. True if the file is connected to a TTY device.");
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001033
1034PyDoc_STRVAR(seekable_doc,
1035"seekable() -> bool. True if file supports random-access.");
1036
1037PyDoc_STRVAR(readable_doc,
1038"readable() -> bool. True if file was opened in a read mode.");
1039
1040PyDoc_STRVAR(writable_doc,
1041"writable() -> bool. True if file was opened in a write mode.");
1042
1043static PyMethodDef fileio_methods[] = {
Antoine Pitroub26dc462010-05-05 16:27:30 +00001044 {"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc},
1045 {"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc},
1046 {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},
1047 {"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc},
1048 {"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc},
1049 {"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc},
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001050#ifdef HAVE_FTRUNCATE
Antoine Pitroub26dc462010-05-05 16:27:30 +00001051 {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001052#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +00001053 {"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc},
1054 {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc},
1055 {"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc},
1056 {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc},
1057 {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc},
1058 {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc},
1059 {NULL, NULL} /* sentinel */
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001060};
1061
1062/* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
1063
1064static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +00001065get_closed(fileio *self, void *closure)
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001066{
Antoine Pitroub26dc462010-05-05 16:27:30 +00001067 return PyBool_FromLong((long)(self->fd < 0));
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001068}
1069
1070static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +00001071get_closefd(fileio *self, void *closure)
Amaury Forgeot d'Arc32265652008-11-20 23:34:31 +00001072{
Antoine Pitroub26dc462010-05-05 16:27:30 +00001073 return PyBool_FromLong((long)(self->closefd));
Amaury Forgeot d'Arc32265652008-11-20 23:34:31 +00001074}
1075
1076static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +00001077get_mode(fileio *self, void *closure)
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001078{
Antoine Pitroub26dc462010-05-05 16:27:30 +00001079 return PyUnicode_FromString(mode_string(self));
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001080}
1081
1082static PyGetSetDef fileio_getsetlist[] = {
Antoine Pitroub26dc462010-05-05 16:27:30 +00001083 {"closed", (getter)get_closed, NULL, "True if the file is closed"},
1084 {"closefd", (getter)get_closefd, NULL,
Serhiy Storchaka46129542015-04-10 16:08:33 +03001085 "True if the file descriptor will be closed by close()."},
Antoine Pitroub26dc462010-05-05 16:27:30 +00001086 {"mode", (getter)get_mode, NULL, "String giving the file mode"},
1087 {NULL},
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001088};
1089
1090PyTypeObject PyFileIO_Type = {
Antoine Pitroub26dc462010-05-05 16:27:30 +00001091 PyVarObject_HEAD_INIT(NULL, 0)
1092 "_io.FileIO",
1093 sizeof(fileio),
1094 0,
1095 (destructor)fileio_dealloc, /* tp_dealloc */
1096 0, /* tp_print */
1097 0, /* tp_getattr */
1098 0, /* tp_setattr */
1099 0, /* tp_reserved */
1100 (reprfunc)fileio_repr, /* tp_repr */
1101 0, /* tp_as_number */
1102 0, /* tp_as_sequence */
1103 0, /* tp_as_mapping */
1104 0, /* tp_hash */
1105 0, /* tp_call */
1106 0, /* tp_str */
1107 PyObject_GenericGetAttr, /* tp_getattro */
1108 0, /* tp_setattro */
1109 0, /* tp_as_buffer */
1110 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
1111 | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1112 fileio_doc, /* tp_doc */
1113 (traverseproc)fileio_traverse, /* tp_traverse */
1114 (inquiry)fileio_clear, /* tp_clear */
1115 0, /* tp_richcompare */
1116 offsetof(fileio, weakreflist), /* tp_weaklistoffset */
1117 0, /* tp_iter */
1118 0, /* tp_iternext */
1119 fileio_methods, /* tp_methods */
1120 0, /* tp_members */
1121 fileio_getsetlist, /* tp_getset */
1122 0, /* tp_base */
1123 0, /* tp_dict */
1124 0, /* tp_descr_get */
1125 0, /* tp_descr_set */
1126 offsetof(fileio, dict), /* tp_dictoffset */
1127 fileio_init, /* tp_init */
1128 PyType_GenericAlloc, /* tp_alloc */
1129 fileio_new, /* tp_new */
1130 PyObject_GC_Del, /* tp_free */
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001131};