blob: 2b40ada195a1f5fd982772e5b4861826e50ac512 [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
Steve Dowerf85dbfc2016-12-28 15:41:09 -080011#ifdef HAVE_IO_H
12#include <io.h>
13#endif
Andrew M. Kuchling4b81bc72010-02-22 23:12:00 +000014#ifdef HAVE_FCNTL_H
Christian Heimes7f39c9f2008-01-25 12:18:43 +000015#include <fcntl.h>
Andrew M. Kuchling4b81bc72010-02-22 23:12:00 +000016#endif
Christian Heimes7f39c9f2008-01-25 12:18:43 +000017#include <stddef.h> /* For offsetof */
Antoine Pitrou19690592009-06-12 20:14:08 +000018#include "_iomodule.h"
Christian Heimes7f39c9f2008-01-25 12:18:43 +000019
20/*
21 * Known likely problems:
22 *
23 * - Files larger then 2**32-1
24 * - Files with unicode filenames
25 * - Passing numbers greater than 2**32-1 when an integer is expected
26 * - Making it work on Windows and other oddball platforms
27 *
28 * To Do:
29 *
30 * - autoconfify header file inclusion
31 */
32
33#ifdef MS_WINDOWS
34/* can simulate truncate with Win32 API functions; see file_truncate */
35#define HAVE_FTRUNCATE
36#define WIN32_LEAN_AND_MEAN
37#include <windows.h>
38#endif
39
Antoine Pitrou19690592009-06-12 20:14:08 +000040#if BUFSIZ < (8*1024)
41#define SMALLCHUNK (8*1024)
42#elif (BUFSIZ >= (2 << 25))
43#error "unreasonable BUFSIZ > 64MB defined"
44#else
45#define SMALLCHUNK BUFSIZ
46#endif
47
Christian Heimes7f39c9f2008-01-25 12:18:43 +000048typedef struct {
Antoine Pitroub26dc462010-05-05 16:27:30 +000049 PyObject_HEAD
50 int fd;
51 unsigned int readable : 1;
52 unsigned int writable : 1;
Antoine Pitrou213fec42013-09-04 20:46:33 +020053 unsigned int appending : 1;
Antoine Pitroub26dc462010-05-05 16:27:30 +000054 signed int seekable : 2; /* -1 means unknown */
55 unsigned int closefd : 1;
56 PyObject *weakreflist;
57 PyObject *dict;
Antoine Pitrou19690592009-06-12 20:14:08 +000058} fileio;
Christian Heimes7f39c9f2008-01-25 12:18:43 +000059
60PyTypeObject PyFileIO_Type;
61
62#define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
63
Antoine Pitrou19690592009-06-12 20:14:08 +000064int
65_PyFileIO_closed(PyObject *self)
66{
Antoine Pitroub26dc462010-05-05 16:27:30 +000067 return ((fileio *)self)->fd < 0;
Antoine Pitrou19690592009-06-12 20:14:08 +000068}
69
Antoine Pitroue741cc62009-01-21 00:45:36 +000070static PyObject *
71portable_lseek(int fd, PyObject *posobj, int whence);
72
Antoine Pitrou19690592009-06-12 20:14:08 +000073static PyObject *portable_lseek(int fd, PyObject *posobj, int whence);
74
75/* Returns 0 on success, -1 with exception set on failure. */
Christian Heimes7f39c9f2008-01-25 12:18:43 +000076static int
Antoine Pitrou19690592009-06-12 20:14:08 +000077internal_close(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +000078{
Antoine Pitroub26dc462010-05-05 16:27:30 +000079 int err = 0;
80 int save_errno = 0;
81 if (self->fd >= 0) {
82 int fd = self->fd;
83 self->fd = -1;
84 /* fd is accessible and someone else may have closed it */
85 if (_PyVerify_fd(fd)) {
86 Py_BEGIN_ALLOW_THREADS
87 err = close(fd);
88 if (err < 0)
89 save_errno = errno;
90 Py_END_ALLOW_THREADS
91 } else {
92 save_errno = errno;
93 err = -1;
94 }
95 }
96 if (err < 0) {
97 errno = save_errno;
98 PyErr_SetFromErrno(PyExc_IOError);
99 return -1;
100 }
101 return 0;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000102}
103
104static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000105fileio_close(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000106{
Serhiy Storchaka3173f7c2015-02-21 00:34:20 +0200107 PyObject *res;
108 res = PyObject_CallMethod((PyObject*)&PyRawIOBase_Type,
109 "close", "O", self);
Antoine Pitroub26dc462010-05-05 16:27:30 +0000110 if (!self->closefd) {
111 self->fd = -1;
Serhiy Storchaka3173f7c2015-02-21 00:34:20 +0200112 return res;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000113 }
Serhiy Storchaka3173f7c2015-02-21 00:34:20 +0200114 if (internal_close(self) < 0)
115 Py_CLEAR(res);
116 return res;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000117}
118
119static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000120fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000121{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000122 fileio *self;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000123
Antoine Pitroub26dc462010-05-05 16:27:30 +0000124 assert(type != NULL && type->tp_alloc != NULL);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000125
Antoine Pitroub26dc462010-05-05 16:27:30 +0000126 self = (fileio *) type->tp_alloc(type, 0);
127 if (self != NULL) {
128 self->fd = -1;
129 self->readable = 0;
130 self->writable = 0;
Antoine Pitrou213fec42013-09-04 20:46:33 +0200131 self->appending = 0;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000132 self->seekable = -1;
133 self->closefd = 1;
134 self->weakreflist = NULL;
135 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000136
Antoine Pitroub26dc462010-05-05 16:27:30 +0000137 return (PyObject *) self;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000138}
139
140/* On Unix, open will succeed for directories.
141 In Python, there should be no file objects referring to
142 directories, so we need a check. */
143
144static int
Antoine Pitrouc2ec9922012-07-06 18:48:24 +0200145dircheck(fileio* self, PyObject *nameobj)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000146{
147#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000148 struct stat buf;
Nir Soffer830daae2017-12-07 22:25:39 +0200149 int res;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000150 if (self->fd < 0)
151 return 0;
Nir Soffer830daae2017-12-07 22:25:39 +0200152
153 Py_BEGIN_ALLOW_THREADS
154 res = fstat(self->fd, &buf);
155 Py_END_ALLOW_THREADS
156
157 if (res == 0 && S_ISDIR(buf.st_mode)) {
Antoine Pitrouc2ec9922012-07-06 18:48:24 +0200158 errno = EISDIR;
159 PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj);
Antoine Pitroub26dc462010-05-05 16:27:30 +0000160 return -1;
161 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000162#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000163 return 0;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000164}
165
Benjamin Peterson5848d1f2009-01-19 00:08:08 +0000166static int
167check_fd(int fd)
168{
169#if defined(HAVE_FSTAT)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000170 struct stat buf;
Nir Soffer830daae2017-12-07 22:25:39 +0200171 int res;
172 PyObject *exc;
173 char *msg;
174
175 if (!_PyVerify_fd(fd)) {
176 goto badfd;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000177 }
Nir Soffer830daae2017-12-07 22:25:39 +0200178
179 Py_BEGIN_ALLOW_THREADS
180 res = fstat(fd, &buf);
181 Py_END_ALLOW_THREADS
182
183 if (res < 0 && errno == EBADF) {
184 goto badfd;
185 }
186
Antoine Pitroub26dc462010-05-05 16:27:30 +0000187 return 0;
Nir Soffer830daae2017-12-07 22:25:39 +0200188
189badfd:
190 msg = strerror(EBADF);
191 exc = PyObject_CallFunction(PyExc_OSError, "(is)",
192 EBADF, msg);
193 PyErr_SetObject(PyExc_OSError, exc);
194 Py_XDECREF(exc);
195 return -1;
196#else
197 return 0;
198#endif
Benjamin Peterson5848d1f2009-01-19 00:08:08 +0000199}
200
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000201
202static int
203fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
204{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000205 fileio *self = (fileio *) oself;
206 static char *kwlist[] = {"file", "mode", "closefd", NULL};
207 const char *name = NULL;
208 PyObject *nameobj, *stringobj = NULL;
209 char *mode = "r";
210 char *s;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000211#ifdef MS_WINDOWS
Antoine Pitroub26dc462010-05-05 16:27:30 +0000212 Py_UNICODE *widename = NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000213#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000214 int ret = 0;
Antoine Pitrou213fec42013-09-04 20:46:33 +0200215 int rwa = 0, plus = 0;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000216 int flags = 0;
217 int fd = -1;
218 int closefd = 1;
Hynek Schlawack9bd4bf22012-06-21 19:45:19 +0200219 int fd_is_own = 0;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000220
Antoine Pitroub26dc462010-05-05 16:27:30 +0000221 assert(PyFileIO_Check(oself));
222 if (self->fd >= 0) {
Hynek Schlawack877effc2012-05-25 09:24:18 +0200223 if (self->closefd) {
224 /* Have to close the existing file first. */
225 if (internal_close(self) < 0)
226 return -1;
227 }
228 else
229 self->fd = -1;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000230 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000231
Antoine Pitroub26dc462010-05-05 16:27:30 +0000232 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:fileio",
233 kwlist, &nameobj, &mode, &closefd))
234 return -1;
Antoine Pitrou19690592009-06-12 20:14:08 +0000235
Antoine Pitroub26dc462010-05-05 16:27:30 +0000236 if (PyFloat_Check(nameobj)) {
237 PyErr_SetString(PyExc_TypeError,
238 "integer argument expected, got float");
239 return -1;
240 }
Antoine Pitrou19690592009-06-12 20:14:08 +0000241
Serhiy Storchaka74f49ab2013-01-19 12:55:39 +0200242 fd = _PyLong_AsInt(nameobj);
Antoine Pitroub26dc462010-05-05 16:27:30 +0000243 if (fd < 0) {
244 if (!PyErr_Occurred()) {
245 PyErr_SetString(PyExc_ValueError,
Serhiy Storchaka46129542015-04-10 16:08:33 +0300246 "negative file descriptor");
Antoine Pitroub26dc462010-05-05 16:27:30 +0000247 return -1;
248 }
249 PyErr_Clear();
250 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000251
Hirokazu Yamamotob24bb272009-05-17 02:52:09 +0000252#ifdef MS_WINDOWS
Serhiy Storchaka3c9ce742016-07-01 23:34:44 +0300253 if (PyUnicode_Check(nameobj)) {
Antoine Pitroub26dc462010-05-05 16:27:30 +0000254 widename = PyUnicode_AS_UNICODE(nameobj);
Serhiy Storchaka3c9ce742016-07-01 23:34:44 +0300255 if (wcslen(widename) != (size_t)PyUnicode_GET_SIZE(nameobj)) {
256 PyErr_SetString(PyExc_TypeError, "embedded NUL character");
257 return -1;
258 }
259 }
Antoine Pitroub26dc462010-05-05 16:27:30 +0000260 if (widename == NULL)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000261#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000262 if (fd < 0)
263 {
264 if (PyBytes_Check(nameobj) || PyByteArray_Check(nameobj)) {
265 Py_ssize_t namelen;
266 if (PyObject_AsCharBuffer(nameobj, &name, &namelen) < 0)
267 return -1;
Serhiy Storchaka3c9ce742016-07-01 23:34:44 +0300268 if (strlen(name) != (size_t)namelen) {
269 PyErr_SetString(PyExc_TypeError, "embedded NUL character");
270 return -1;
271 }
Antoine Pitroub26dc462010-05-05 16:27:30 +0000272 }
273 else {
274 PyObject *u = PyUnicode_FromObject(nameobj);
Antoine Pitrou19690592009-06-12 20:14:08 +0000275
Antoine Pitroub26dc462010-05-05 16:27:30 +0000276 if (u == NULL)
277 return -1;
Antoine Pitrou19690592009-06-12 20:14:08 +0000278
Antoine Pitroub26dc462010-05-05 16:27:30 +0000279 stringobj = PyUnicode_AsEncodedString(
280 u, Py_FileSystemDefaultEncoding, NULL);
281 Py_DECREF(u);
282 if (stringobj == NULL)
283 return -1;
284 if (!PyBytes_Check(stringobj)) {
285 PyErr_SetString(PyExc_TypeError,
286 "encoder failed to return bytes");
287 goto error;
288 }
289 name = PyBytes_AS_STRING(stringobj);
Serhiy Storchaka3c9ce742016-07-01 23:34:44 +0300290 if (strlen(name) != (size_t)PyBytes_GET_SIZE(stringobj)) {
291 PyErr_SetString(PyExc_TypeError, "embedded NUL character");
292 goto error;
293 }
Antoine Pitroub26dc462010-05-05 16:27:30 +0000294 }
295 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000296
Antoine Pitroub26dc462010-05-05 16:27:30 +0000297 s = mode;
298 while (*s) {
299 switch (*s++) {
300 case 'r':
301 if (rwa) {
302 bad_mode:
303 PyErr_SetString(PyExc_ValueError,
Georg Brandl10603802010-11-26 08:10:41 +0000304 "Must have exactly one of read/write/append "
305 "mode and at most one plus");
Antoine Pitroub26dc462010-05-05 16:27:30 +0000306 goto error;
307 }
308 rwa = 1;
309 self->readable = 1;
310 break;
311 case 'w':
312 if (rwa)
313 goto bad_mode;
314 rwa = 1;
315 self->writable = 1;
316 flags |= O_CREAT | O_TRUNC;
317 break;
318 case 'a':
319 if (rwa)
320 goto bad_mode;
321 rwa = 1;
322 self->writable = 1;
Antoine Pitrou213fec42013-09-04 20:46:33 +0200323 self->appending = 1;
324 flags |= O_APPEND | O_CREAT;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000325 break;
326 case 'b':
327 break;
328 case '+':
329 if (plus)
330 goto bad_mode;
331 self->readable = self->writable = 1;
332 plus = 1;
333 break;
334 default:
335 PyErr_Format(PyExc_ValueError,
336 "invalid mode: %.200s", mode);
337 goto error;
338 }
339 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000340
Antoine Pitroub26dc462010-05-05 16:27:30 +0000341 if (!rwa)
342 goto bad_mode;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000343
Antoine Pitroub26dc462010-05-05 16:27:30 +0000344 if (self->readable && self->writable)
345 flags |= O_RDWR;
346 else if (self->readable)
347 flags |= O_RDONLY;
348 else
349 flags |= O_WRONLY;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000350
351#ifdef O_BINARY
Antoine Pitroub26dc462010-05-05 16:27:30 +0000352 flags |= O_BINARY;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000353#endif
354
Antoine Pitroub26dc462010-05-05 16:27:30 +0000355 if (fd >= 0) {
356 if (check_fd(fd))
357 goto error;
358 self->fd = fd;
359 self->closefd = closefd;
360 }
361 else {
362 self->closefd = 1;
363 if (!closefd) {
364 PyErr_SetString(PyExc_ValueError,
365 "Cannot use closefd=False with file name");
366 goto error;
367 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000368
Antoine Pitroub26dc462010-05-05 16:27:30 +0000369 Py_BEGIN_ALLOW_THREADS
370 errno = 0;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000371#ifdef MS_WINDOWS
Antoine Pitroub26dc462010-05-05 16:27:30 +0000372 if (widename != NULL)
373 self->fd = _wopen(widename, flags, 0666);
374 else
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000375#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000376 self->fd = open(name, flags, 0666);
377 Py_END_ALLOW_THREADS
Hynek Schlawack9bd4bf22012-06-21 19:45:19 +0200378 fd_is_own = 1;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000379 if (self->fd < 0) {
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000380#ifdef MS_WINDOWS
Antoine Pitroub26dc462010-05-05 16:27:30 +0000381 if (widename != NULL)
382 PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename);
383 else
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000384#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000385 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
386 goto error;
387 }
Antoine Pitroub26dc462010-05-05 16:27:30 +0000388 }
Antoine Pitrouc2ec9922012-07-06 18:48:24 +0200389 if (dircheck(self, nameobj) < 0)
390 goto error;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000391
Antoine Pitroub26dc462010-05-05 16:27:30 +0000392 if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0)
393 goto error;
Antoine Pitrou19690592009-06-12 20:14:08 +0000394
Antoine Pitrou213fec42013-09-04 20:46:33 +0200395 if (self->appending) {
Antoine Pitroub26dc462010-05-05 16:27:30 +0000396 /* For consistent behaviour, we explicitly seek to the
397 end of file (otherwise, it might be done only on the
398 first write()). */
399 PyObject *pos = portable_lseek(self->fd, NULL, 2);
Hynek Schlawack9bd4bf22012-06-21 19:45:19 +0200400 if (pos == NULL)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000401 goto error;
402 Py_DECREF(pos);
403 }
Antoine Pitroue741cc62009-01-21 00:45:36 +0000404
Antoine Pitroub26dc462010-05-05 16:27:30 +0000405 goto done;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000406
407 error:
Hynek Schlawack9bd4bf22012-06-21 19:45:19 +0200408 if (!fd_is_own)
409 self->fd = -1;
410
Antoine Pitroub26dc462010-05-05 16:27:30 +0000411 ret = -1;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000412
413 done:
Antoine Pitroub26dc462010-05-05 16:27:30 +0000414 Py_CLEAR(stringobj);
415 return ret;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000416}
417
Antoine Pitrou19690592009-06-12 20:14:08 +0000418static int
419fileio_traverse(fileio *self, visitproc visit, void *arg)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000420{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000421 Py_VISIT(self->dict);
422 return 0;
Antoine Pitrou19690592009-06-12 20:14:08 +0000423}
424
425static int
426fileio_clear(fileio *self)
427{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000428 Py_CLEAR(self->dict);
429 return 0;
Antoine Pitrou19690592009-06-12 20:14:08 +0000430}
431
432static void
433fileio_dealloc(fileio *self)
434{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000435 if (_PyIOBase_finalize((PyObject *) self) < 0)
436 return;
437 _PyObject_GC_UNTRACK(self);
438 if (self->weakreflist != NULL)
439 PyObject_ClearWeakRefs((PyObject *) self);
440 Py_CLEAR(self->dict);
441 Py_TYPE(self)->tp_free((PyObject *)self);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000442}
443
444static PyObject *
445err_closed(void)
446{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000447 PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
448 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000449}
450
451static PyObject *
452err_mode(char *action)
453{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000454 PyErr_Format(PyExc_ValueError, "File not open for %s", action);
455 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000456}
457
458static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000459fileio_fileno(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000460{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000461 if (self->fd < 0)
462 return err_closed();
463 return PyInt_FromLong((long) self->fd);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000464}
465
466static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000467fileio_readable(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000468{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000469 if (self->fd < 0)
470 return err_closed();
471 return PyBool_FromLong((long) self->readable);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000472}
473
474static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000475fileio_writable(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000476{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000477 if (self->fd < 0)
478 return err_closed();
479 return PyBool_FromLong((long) self->writable);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000480}
481
482static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000483fileio_seekable(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000484{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000485 if (self->fd < 0)
486 return err_closed();
487 if (self->seekable < 0) {
488 PyObject *pos = portable_lseek(self->fd, NULL, SEEK_CUR);
489 if (pos == NULL) {
490 PyErr_Clear();
491 self->seekable = 0;
492 } else {
493 Py_DECREF(pos);
494 self->seekable = 1;
495 }
496 }
497 return PyBool_FromLong((long) self->seekable);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000498}
499
500static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000501fileio_readinto(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000502{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000503 Py_buffer pbuf;
Victor Stinner59729ff2011-07-05 11:28:19 +0200504 Py_ssize_t n, len;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000505
Antoine Pitroub26dc462010-05-05 16:27:30 +0000506 if (self->fd < 0)
507 return err_closed();
508 if (!self->readable)
509 return err_mode("reading");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000510
Antoine Pitroub26dc462010-05-05 16:27:30 +0000511 if (!PyArg_ParseTuple(args, "w*", &pbuf))
512 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000513
Antoine Pitroub26dc462010-05-05 16:27:30 +0000514 if (_PyVerify_fd(self->fd)) {
Victor Stinner59729ff2011-07-05 11:28:19 +0200515 len = pbuf.len;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000516 Py_BEGIN_ALLOW_THREADS
517 errno = 0;
Victor Stinner59729ff2011-07-05 11:28:19 +0200518#if defined(MS_WIN64) || defined(MS_WINDOWS)
519 if (len > INT_MAX)
520 len = INT_MAX;
521 n = read(self->fd, pbuf.buf, (int)len);
522#else
523 n = read(self->fd, pbuf.buf, len);
524#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000525 Py_END_ALLOW_THREADS
526 } else
527 n = -1;
528 PyBuffer_Release(&pbuf);
529 if (n < 0) {
530 if (errno == EAGAIN)
531 Py_RETURN_NONE;
532 PyErr_SetFromErrno(PyExc_IOError);
533 return NULL;
534 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000535
Antoine Pitroub26dc462010-05-05 16:27:30 +0000536 return PyLong_FromSsize_t(n);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000537}
538
Antoine Pitrou19690592009-06-12 20:14:08 +0000539static size_t
540new_buffersize(fileio *self, size_t currentsize)
541{
542#ifdef HAVE_FSTAT
Antoine Pitroub26dc462010-05-05 16:27:30 +0000543 off_t pos, end;
544 struct stat st;
Nir Soffer830daae2017-12-07 22:25:39 +0200545 int res;
546
547 Py_BEGIN_ALLOW_THREADS
548 res = fstat(self->fd, &st);
549 Py_END_ALLOW_THREADS
550
551 if (res == 0) {
Antoine Pitroub26dc462010-05-05 16:27:30 +0000552 end = st.st_size;
Nir Soffer830daae2017-12-07 22:25:39 +0200553
554 Py_BEGIN_ALLOW_THREADS
Antoine Pitroub26dc462010-05-05 16:27:30 +0000555 pos = lseek(self->fd, 0L, SEEK_CUR);
Nir Soffer830daae2017-12-07 22:25:39 +0200556 Py_END_ALLOW_THREADS
557
Antoine Pitroub26dc462010-05-05 16:27:30 +0000558 /* Files claiming a size smaller than SMALLCHUNK may
559 actually be streaming pseudo-files. In this case, we
560 apply the more aggressive algorithm below.
561 */
562 if (end >= SMALLCHUNK && end >= pos && pos >= 0) {
563 /* Add 1 so if the file were to grow we'd notice. */
564 return currentsize + end - pos + 1;
565 }
566 }
Antoine Pitrou19690592009-06-12 20:14:08 +0000567#endif
Nadeem Vawda36248152011-10-13 13:52:46 +0200568 /* Expand the buffer by an amount proportional to the current size,
569 giving us amortized linear-time behavior. Use a less-than-double
570 growth factor to avoid excessive allocation. */
571 return currentsize + (currentsize >> 3) + 6;
Antoine Pitrou19690592009-06-12 20:14:08 +0000572}
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000573
574static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000575fileio_readall(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000576{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000577 PyObject *result;
578 Py_ssize_t total = 0;
Victor Stinner23a32ba2013-01-03 03:33:21 +0100579 Py_ssize_t n;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000580
Victor Stinner5100a402011-05-25 22:15:36 +0200581 if (self->fd < 0)
582 return err_closed();
Antoine Pitroub26dc462010-05-05 16:27:30 +0000583 if (!_PyVerify_fd(self->fd))
584 return PyErr_SetFromErrno(PyExc_IOError);
Antoine Pitrou19690592009-06-12 20:14:08 +0000585
Antoine Pitroub26dc462010-05-05 16:27:30 +0000586 result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
587 if (result == NULL)
588 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000589
Antoine Pitroub26dc462010-05-05 16:27:30 +0000590 while (1) {
591 size_t newsize = new_buffersize(self, total);
592 if (newsize > PY_SSIZE_T_MAX || newsize <= 0) {
593 PyErr_SetString(PyExc_OverflowError,
594 "unbounded read returned more bytes "
595 "than a Python string can hold ");
596 Py_DECREF(result);
597 return NULL;
598 }
Antoine Pitrou19690592009-06-12 20:14:08 +0000599
Antoine Pitroub26dc462010-05-05 16:27:30 +0000600 if (PyBytes_GET_SIZE(result) < (Py_ssize_t)newsize) {
Kristján Valur Jónssonbe580f22014-04-25 09:51:21 +0000601 if (_PyBytes_Resize(&result, newsize) < 0)
602 return NULL; /* result has been freed */
Antoine Pitroub26dc462010-05-05 16:27:30 +0000603 }
604 Py_BEGIN_ALLOW_THREADS
605 errno = 0;
Victor Stinner23a32ba2013-01-03 03:33:21 +0100606 n = newsize - total;
607#if defined(MS_WIN64) || defined(MS_WINDOWS)
608 if (n > INT_MAX)
609 n = INT_MAX;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000610 n = read(self->fd,
611 PyBytes_AS_STRING(result) + total,
Victor Stinner23a32ba2013-01-03 03:33:21 +0100612 (int)n);
613#else
614 n = read(self->fd,
615 PyBytes_AS_STRING(result) + total,
616 n);
617#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000618 Py_END_ALLOW_THREADS
619 if (n == 0)
620 break;
621 if (n < 0) {
Gregory P. Smith99716162012-10-12 13:02:06 -0700622 if (errno == EINTR) {
623 if (PyErr_CheckSignals()) {
624 Py_DECREF(result);
625 return NULL;
626 }
627 continue;
628 }
Antoine Pitroub26dc462010-05-05 16:27:30 +0000629 if (errno == EAGAIN) {
Victor Stinnerf6b3c842014-07-02 23:12:48 +0200630 if (total > 0)
631 break;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000632 Py_DECREF(result);
633 Py_RETURN_NONE;
634 }
635 Py_DECREF(result);
636 PyErr_SetFromErrno(PyExc_IOError);
637 return NULL;
638 }
639 total += n;
640 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000641
Antoine Pitroub26dc462010-05-05 16:27:30 +0000642 if (PyBytes_GET_SIZE(result) > total) {
643 if (_PyBytes_Resize(&result, total) < 0) {
644 /* This should never happen, but just in case */
Antoine Pitroub26dc462010-05-05 16:27:30 +0000645 return NULL;
646 }
647 }
648 return result;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000649}
650
651static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000652fileio_read(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000653{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000654 char *ptr;
655 Py_ssize_t n;
656 Py_ssize_t size = -1;
657 PyObject *bytes;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000658
Antoine Pitroub26dc462010-05-05 16:27:30 +0000659 if (self->fd < 0)
660 return err_closed();
661 if (!self->readable)
662 return err_mode("reading");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000663
Antoine Pitroub26dc462010-05-05 16:27:30 +0000664 if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size))
665 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000666
Antoine Pitroub26dc462010-05-05 16:27:30 +0000667 if (size < 0) {
668 return fileio_readall(self);
669 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000670
Victor Stinner59729ff2011-07-05 11:28:19 +0200671#if defined(MS_WIN64) || defined(MS_WINDOWS)
672 if (size > INT_MAX)
673 size = INT_MAX;
674#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000675 bytes = PyBytes_FromStringAndSize(NULL, size);
676 if (bytes == NULL)
677 return NULL;
678 ptr = PyBytes_AS_STRING(bytes);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000679
Antoine Pitroub26dc462010-05-05 16:27:30 +0000680 if (_PyVerify_fd(self->fd)) {
681 Py_BEGIN_ALLOW_THREADS
682 errno = 0;
Victor Stinner59729ff2011-07-05 11:28:19 +0200683#if defined(MS_WIN64) || defined(MS_WINDOWS)
684 n = read(self->fd, ptr, (int)size);
685#else
Antoine Pitroub26dc462010-05-05 16:27:30 +0000686 n = read(self->fd, ptr, size);
Victor Stinner59729ff2011-07-05 11:28:19 +0200687#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000688 Py_END_ALLOW_THREADS
689 } else
690 n = -1;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000691
Antoine Pitroub26dc462010-05-05 16:27:30 +0000692 if (n < 0) {
693 Py_DECREF(bytes);
694 if (errno == EAGAIN)
695 Py_RETURN_NONE;
696 PyErr_SetFromErrno(PyExc_IOError);
697 return NULL;
698 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000699
Antoine Pitroub26dc462010-05-05 16:27:30 +0000700 if (n != size) {
Kristján Valur Jónssonbe580f22014-04-25 09:51:21 +0000701 if (_PyBytes_Resize(&bytes, n) < 0)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000702 return NULL;
Antoine Pitroub26dc462010-05-05 16:27:30 +0000703 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000704
Antoine Pitroub26dc462010-05-05 16:27:30 +0000705 return (PyObject *) bytes;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000706}
707
708static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000709fileio_write(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000710{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000711 Py_buffer pbuf;
Victor Stinner59729ff2011-07-05 11:28:19 +0200712 Py_ssize_t n, len;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000713
Antoine Pitroub26dc462010-05-05 16:27:30 +0000714 if (self->fd < 0)
715 return err_closed();
716 if (!self->writable)
717 return err_mode("writing");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000718
Antoine Pitroub26dc462010-05-05 16:27:30 +0000719 if (!PyArg_ParseTuple(args, "s*", &pbuf))
720 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000721
Antoine Pitroub26dc462010-05-05 16:27:30 +0000722 if (_PyVerify_fd(self->fd)) {
723 Py_BEGIN_ALLOW_THREADS
724 errno = 0;
Victor Stinner59729ff2011-07-05 11:28:19 +0200725 len = pbuf.len;
726#if defined(MS_WIN64) || defined(MS_WINDOWS)
727 if (len > INT_MAX)
728 len = INT_MAX;
729 n = write(self->fd, pbuf.buf, (int)len);
730#else
731 n = write(self->fd, pbuf.buf, len);
732#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000733 Py_END_ALLOW_THREADS
734 } else
735 n = -1;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000736
Antoine Pitroub26dc462010-05-05 16:27:30 +0000737 PyBuffer_Release(&pbuf);
Martin v. Löwisf91d46a2008-08-12 14:49:50 +0000738
Antoine Pitroub26dc462010-05-05 16:27:30 +0000739 if (n < 0) {
740 if (errno == EAGAIN)
741 Py_RETURN_NONE;
742 PyErr_SetFromErrno(PyExc_IOError);
743 return NULL;
744 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000745
Antoine Pitroub26dc462010-05-05 16:27:30 +0000746 return PyLong_FromSsize_t(n);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000747}
748
749/* XXX Windows support below is likely incomplete */
750
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000751/* Cribbed from posix_lseek() */
752static PyObject *
753portable_lseek(int fd, PyObject *posobj, int whence)
754{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000755 Py_off_t pos, res;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000756
757#ifdef SEEK_SET
Antoine Pitroub26dc462010-05-05 16:27:30 +0000758 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
759 switch (whence) {
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000760#if SEEK_SET != 0
Antoine Pitroub26dc462010-05-05 16:27:30 +0000761 case 0: whence = SEEK_SET; break;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000762#endif
763#if SEEK_CUR != 1
Antoine Pitroub26dc462010-05-05 16:27:30 +0000764 case 1: whence = SEEK_CUR; break;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000765#endif
Benjamin Peterson8024cec2009-01-20 14:31:08 +0000766#if SEEK_END != 2
Antoine Pitroub26dc462010-05-05 16:27:30 +0000767 case 2: whence = SEEK_END; break;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000768#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000769 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000770#endif /* SEEK_SET */
771
Antoine Pitroub26dc462010-05-05 16:27:30 +0000772 if (posobj == NULL)
773 pos = 0;
774 else {
775 if(PyFloat_Check(posobj)) {
776 PyErr_SetString(PyExc_TypeError, "an integer is required");
777 return NULL;
778 }
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000779#if defined(HAVE_LARGEFILE_SUPPORT)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000780 pos = PyLong_AsLongLong(posobj);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000781#else
Antoine Pitroub26dc462010-05-05 16:27:30 +0000782 pos = PyLong_AsLong(posobj);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000783#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000784 if (PyErr_Occurred())
785 return NULL;
786 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000787
Antoine Pitroub26dc462010-05-05 16:27:30 +0000788 if (_PyVerify_fd(fd)) {
789 Py_BEGIN_ALLOW_THREADS
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000790#if defined(MS_WIN64) || defined(MS_WINDOWS)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000791 res = _lseeki64(fd, pos, whence);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000792#else
Antoine Pitroub26dc462010-05-05 16:27:30 +0000793 res = lseek(fd, pos, whence);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000794#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000795 Py_END_ALLOW_THREADS
796 } else
797 res = -1;
798 if (res < 0)
799 return PyErr_SetFromErrno(PyExc_IOError);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000800
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000801#if defined(HAVE_LARGEFILE_SUPPORT)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000802 return PyLong_FromLongLong(res);
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000803#else
Antoine Pitroub26dc462010-05-05 16:27:30 +0000804 return PyLong_FromLong(res);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000805#endif
806}
807
808static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000809fileio_seek(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000810{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000811 PyObject *posobj;
812 int whence = 0;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000813
Antoine Pitroub26dc462010-05-05 16:27:30 +0000814 if (self->fd < 0)
815 return err_closed();
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000816
Antoine Pitroub26dc462010-05-05 16:27:30 +0000817 if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))
818 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000819
Antoine Pitroub26dc462010-05-05 16:27:30 +0000820 return portable_lseek(self->fd, posobj, whence);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000821}
822
823static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000824fileio_tell(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000825{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000826 if (self->fd < 0)
827 return err_closed();
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000828
Antoine Pitroub26dc462010-05-05 16:27:30 +0000829 return portable_lseek(self->fd, NULL, 1);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000830}
831
832#ifdef HAVE_FTRUNCATE
833static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000834fileio_truncate(fileio *self, PyObject *args)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000835{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000836 PyObject *posobj = NULL; /* the new size wanted by the user */
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000837#ifndef MS_WINDOWS
Antoine Pitroub26dc462010-05-05 16:27:30 +0000838 Py_off_t pos;
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000839#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000840 int ret;
841 int fd;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000842
Antoine Pitroub26dc462010-05-05 16:27:30 +0000843 fd = self->fd;
844 if (fd < 0)
845 return err_closed();
846 if (!self->writable)
847 return err_mode("writing");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000848
Antoine Pitroub26dc462010-05-05 16:27:30 +0000849 if (!PyArg_ParseTuple(args, "|O", &posobj))
850 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000851
Antoine Pitroub26dc462010-05-05 16:27:30 +0000852 if (posobj == Py_None || posobj == NULL) {
853 /* Get the current position. */
854 posobj = portable_lseek(fd, NULL, 1);
855 if (posobj == NULL)
856 return NULL;
857 }
858 else {
859 Py_INCREF(posobj);
860 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000861
862#ifdef MS_WINDOWS
Antoine Pitroub26dc462010-05-05 16:27:30 +0000863 /* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
864 so don't even try using it. */
865 {
866 PyObject *oldposobj, *tempposobj;
867 HANDLE hFile;
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000868
Antoine Pitroub26dc462010-05-05 16:27:30 +0000869 /* we save the file pointer position */
870 oldposobj = portable_lseek(fd, NULL, 1);
871 if (oldposobj == NULL) {
872 Py_DECREF(posobj);
873 return NULL;
874 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000875
Antoine Pitroub26dc462010-05-05 16:27:30 +0000876 /* we then move to the truncation position */
877 tempposobj = portable_lseek(fd, posobj, 0);
878 if (tempposobj == NULL) {
879 Py_DECREF(oldposobj);
880 Py_DECREF(posobj);
881 return NULL;
882 }
883 Py_DECREF(tempposobj);
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000884
Antoine Pitroub26dc462010-05-05 16:27:30 +0000885 /* Truncate. Note that this may grow the file! */
886 Py_BEGIN_ALLOW_THREADS
887 errno = 0;
888 hFile = (HANDLE)_get_osfhandle(fd);
889 ret = hFile == (HANDLE)-1; /* testing for INVALID_HANDLE value */
890 if (ret == 0) {
891 ret = SetEndOfFile(hFile) == 0;
892 if (ret)
893 errno = EACCES;
894 }
895 Py_END_ALLOW_THREADS
896
897 /* we restore the file pointer position in any case */
898 tempposobj = portable_lseek(fd, oldposobj, 0);
899 Py_DECREF(oldposobj);
900 if (tempposobj == NULL) {
901 Py_DECREF(posobj);
902 return NULL;
903 }
904 Py_DECREF(tempposobj);
905 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000906#else
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000907
908#if defined(HAVE_LARGEFILE_SUPPORT)
Antoine Pitroub26dc462010-05-05 16:27:30 +0000909 pos = PyLong_AsLongLong(posobj);
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000910#else
Antoine Pitroub26dc462010-05-05 16:27:30 +0000911 pos = PyLong_AsLong(posobj);
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000912#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +0000913 if (PyErr_Occurred()){
914 Py_DECREF(posobj);
915 return NULL;
916 }
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000917
Antoine Pitroub26dc462010-05-05 16:27:30 +0000918 Py_BEGIN_ALLOW_THREADS
919 errno = 0;
920 ret = ftruncate(fd, pos);
921 Py_END_ALLOW_THREADS
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000922
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000923#endif /* !MS_WINDOWS */
924
Antoine Pitroub26dc462010-05-05 16:27:30 +0000925 if (ret != 0) {
926 Py_DECREF(posobj);
927 PyErr_SetFromErrno(PyExc_IOError);
928 return NULL;
929 }
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000930
Antoine Pitroub26dc462010-05-05 16:27:30 +0000931 return posobj;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000932}
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000933#endif /* HAVE_FTRUNCATE */
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000934
935static char *
Antoine Pitrou19690592009-06-12 20:14:08 +0000936mode_string(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000937{
Antoine Pitrou213fec42013-09-04 20:46:33 +0200938 if (self->appending) {
939 if (self->readable)
940 return "ab+";
941 else
942 return "ab";
943 }
944 else if (self->readable) {
Antoine Pitroub26dc462010-05-05 16:27:30 +0000945 if (self->writable)
946 return "rb+";
947 else
948 return "rb";
949 }
950 else
951 return "wb";
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000952}
953
954static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000955fileio_repr(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000956{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000957 PyObject *nameobj, *res;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000958
Antoine Pitroub26dc462010-05-05 16:27:30 +0000959 if (self->fd < 0)
960 return PyString_FromFormat("<_io.FileIO [closed]>");
Antoine Pitrou19690592009-06-12 20:14:08 +0000961
Antoine Pitroub26dc462010-05-05 16:27:30 +0000962 nameobj = PyObject_GetAttrString((PyObject *) self, "name");
963 if (nameobj == NULL) {
964 if (PyErr_ExceptionMatches(PyExc_AttributeError))
965 PyErr_Clear();
966 else
967 return NULL;
968 res = PyString_FromFormat("<_io.FileIO fd=%d mode='%s'>",
969 self->fd, mode_string(self));
970 }
971 else {
972 PyObject *repr = PyObject_Repr(nameobj);
973 Py_DECREF(nameobj);
974 if (repr == NULL)
975 return NULL;
976 res = PyString_FromFormat("<_io.FileIO name=%s mode='%s'>",
977 PyString_AS_STRING(repr),
978 mode_string(self));
979 Py_DECREF(repr);
980 }
981 return res;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000982}
983
984static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +0000985fileio_isatty(fileio *self)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000986{
Antoine Pitroub26dc462010-05-05 16:27:30 +0000987 long res;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000988
Antoine Pitroub26dc462010-05-05 16:27:30 +0000989 if (self->fd < 0)
990 return err_closed();
991 Py_BEGIN_ALLOW_THREADS
992 res = isatty(self->fd);
993 Py_END_ALLOW_THREADS
994 return PyBool_FromLong(res);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000995}
996
997
998PyDoc_STRVAR(fileio_doc,
999"file(name: str[, mode: str]) -> file IO object\n"
1000"\n"
Serhiy Storchaka46129542015-04-10 16:08:33 +03001001"Open a file. The mode can be 'r' (default), 'w' or 'a' for reading,\n"
Antoine Pitroub26dc462010-05-05 16:27:30 +00001002"writing or appending. The file will be created if it doesn't exist\n"
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001003"when opened for writing or appending; it will be truncated when\n"
1004"opened for writing. Add a '+' to the mode to allow simultaneous\n"
1005"reading and writing.");
1006
1007PyDoc_STRVAR(read_doc,
1008"read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"
1009"\n"
1010"Only makes one system call, so less data may be returned than requested\n"
1011"In non-blocking mode, returns None if no data is available.\n"
1012"On end-of-file, returns ''.");
1013
1014PyDoc_STRVAR(readall_doc,
1015"readall() -> bytes. read all data from the file, returned as bytes.\n"
1016"\n"
1017"In non-blocking mode, returns as much as is immediately available,\n"
1018"or None if no data is available. On end-of-file, returns ''.");
1019
1020PyDoc_STRVAR(write_doc,
Martin Panterc9813d82016-06-03 05:59:20 +00001021"write(b) -> int. Write array of bytes b, return number written.\n"
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001022"\n"
1023"Only makes one system call, so not all of the data may be written.\n"
Serhiy Storchaka46129542015-04-10 16:08:33 +03001024"The number of bytes actually written is returned. In non-blocking mode,\n"
1025"returns None if the write would block."
1026);
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001027
1028PyDoc_STRVAR(fileno_doc,
Serhiy Storchaka46129542015-04-10 16:08:33 +03001029"fileno() -> int. Return the underlying file descriptor (an integer).");
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001030
1031PyDoc_STRVAR(seek_doc,
Berker Peksagb5dc3dc2014-09-24 12:54:25 +03001032"seek(offset: int[, whence: int]) -> int. Move to new file position\n"
1033"and return the file position.\n"
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001034"\n"
1035"Argument offset is a byte count. Optional argument whence defaults to\n"
Serhiy Storchaka46129542015-04-10 16:08:33 +03001036"SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n"
1037"are SEEK_CUR or 1 (move relative to current position, positive or negative),\n"
1038"and SEEK_END or 2 (move relative to end of file, usually negative, although\n"
1039"many platforms allow seeking beyond the end of a file).\n"
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001040"\n"
1041"Note that not all file objects are seekable.");
1042
1043#ifdef HAVE_FTRUNCATE
1044PyDoc_STRVAR(truncate_doc,
Berker Peksagb5dc3dc2014-09-24 12:54:25 +03001045"truncate([size: int]) -> int. Truncate the file to at most size bytes and\n"
1046"return the truncated size.\n"
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001047"\n"
Berker Peksagb5dc3dc2014-09-24 12:54:25 +03001048"Size defaults to the current file position, as returned by tell().\n"
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +00001049"The current file position is changed to the value of size.");
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001050#endif
1051
1052PyDoc_STRVAR(tell_doc,
Serhiy Storchaka46129542015-04-10 16:08:33 +03001053"tell() -> int. Current file position.\n"
1054"\n"
1055"Can raise OSError for non seekable files."
1056);
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001057
1058PyDoc_STRVAR(readinto_doc,
Antoine Pitrou19690592009-06-12 20:14:08 +00001059"readinto() -> Same as RawIOBase.readinto().");
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001060
1061PyDoc_STRVAR(close_doc,
1062"close() -> None. Close the file.\n"
1063"\n"
1064"A closed file cannot be used for further I/O operations. close() may be\n"
Serhiy Storchaka46129542015-04-10 16:08:33 +03001065"called more than once without error.");
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001066
1067PyDoc_STRVAR(isatty_doc,
Serhiy Storchaka46129542015-04-10 16:08:33 +03001068"isatty() -> bool. True if the file is connected to a TTY device.");
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001069
1070PyDoc_STRVAR(seekable_doc,
1071"seekable() -> bool. True if file supports random-access.");
1072
1073PyDoc_STRVAR(readable_doc,
1074"readable() -> bool. True if file was opened in a read mode.");
1075
1076PyDoc_STRVAR(writable_doc,
1077"writable() -> bool. True if file was opened in a write mode.");
1078
1079static PyMethodDef fileio_methods[] = {
Antoine Pitroub26dc462010-05-05 16:27:30 +00001080 {"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc},
1081 {"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc},
1082 {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},
1083 {"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc},
1084 {"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc},
1085 {"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc},
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001086#ifdef HAVE_FTRUNCATE
Antoine Pitroub26dc462010-05-05 16:27:30 +00001087 {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001088#endif
Antoine Pitroub26dc462010-05-05 16:27:30 +00001089 {"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc},
1090 {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc},
1091 {"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc},
1092 {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc},
1093 {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc},
1094 {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc},
1095 {NULL, NULL} /* sentinel */
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001096};
1097
1098/* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
1099
1100static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +00001101get_closed(fileio *self, void *closure)
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001102{
Antoine Pitroub26dc462010-05-05 16:27:30 +00001103 return PyBool_FromLong((long)(self->fd < 0));
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001104}
1105
1106static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +00001107get_closefd(fileio *self, void *closure)
Amaury Forgeot d'Arc32265652008-11-20 23:34:31 +00001108{
Antoine Pitroub26dc462010-05-05 16:27:30 +00001109 return PyBool_FromLong((long)(self->closefd));
Amaury Forgeot d'Arc32265652008-11-20 23:34:31 +00001110}
1111
1112static PyObject *
Antoine Pitrou19690592009-06-12 20:14:08 +00001113get_mode(fileio *self, void *closure)
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001114{
Antoine Pitroub26dc462010-05-05 16:27:30 +00001115 return PyUnicode_FromString(mode_string(self));
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001116}
1117
1118static PyGetSetDef fileio_getsetlist[] = {
Antoine Pitroub26dc462010-05-05 16:27:30 +00001119 {"closed", (getter)get_closed, NULL, "True if the file is closed"},
1120 {"closefd", (getter)get_closefd, NULL,
Serhiy Storchaka46129542015-04-10 16:08:33 +03001121 "True if the file descriptor will be closed by close()."},
Antoine Pitroub26dc462010-05-05 16:27:30 +00001122 {"mode", (getter)get_mode, NULL, "String giving the file mode"},
1123 {NULL},
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001124};
1125
1126PyTypeObject PyFileIO_Type = {
Antoine Pitroub26dc462010-05-05 16:27:30 +00001127 PyVarObject_HEAD_INIT(NULL, 0)
1128 "_io.FileIO",
1129 sizeof(fileio),
1130 0,
1131 (destructor)fileio_dealloc, /* tp_dealloc */
1132 0, /* tp_print */
1133 0, /* tp_getattr */
1134 0, /* tp_setattr */
1135 0, /* tp_reserved */
1136 (reprfunc)fileio_repr, /* tp_repr */
1137 0, /* tp_as_number */
1138 0, /* tp_as_sequence */
1139 0, /* tp_as_mapping */
1140 0, /* tp_hash */
1141 0, /* tp_call */
1142 0, /* tp_str */
1143 PyObject_GenericGetAttr, /* tp_getattro */
1144 0, /* tp_setattro */
1145 0, /* tp_as_buffer */
1146 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
1147 | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1148 fileio_doc, /* tp_doc */
1149 (traverseproc)fileio_traverse, /* tp_traverse */
1150 (inquiry)fileio_clear, /* tp_clear */
1151 0, /* tp_richcompare */
1152 offsetof(fileio, weakreflist), /* tp_weaklistoffset */
1153 0, /* tp_iter */
1154 0, /* tp_iternext */
1155 fileio_methods, /* tp_methods */
1156 0, /* tp_members */
1157 fileio_getsetlist, /* tp_getset */
1158 0, /* tp_base */
1159 0, /* tp_dict */
1160 0, /* tp_descr_get */
1161 0, /* tp_descr_set */
1162 offsetof(fileio, dict), /* tp_dictoffset */
1163 fileio_init, /* tp_init */
1164 PyType_GenericAlloc, /* tp_alloc */
1165 fileio_new, /* tp_new */
1166 PyObject_GC_Del, /* tp_free */
Christian Heimes7f39c9f2008-01-25 12:18:43 +00001167};