blob: ca12822e1db043aca5f8b9e5aa4210b6d7cfd6ea [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"
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <stddef.h> /* For offsetof */
9
10/*
11 * Known likely problems:
12 *
13 * - Files larger then 2**32-1
14 * - Files with unicode filenames
15 * - Passing numbers greater than 2**32-1 when an integer is expected
16 * - Making it work on Windows and other oddball platforms
17 *
18 * To Do:
19 *
20 * - autoconfify header file inclusion
21 */
22
23#ifdef MS_WINDOWS
24/* can simulate truncate with Win32 API functions; see file_truncate */
25#define HAVE_FTRUNCATE
26#define WIN32_LEAN_AND_MEAN
27#include <windows.h>
28#endif
29
30typedef struct {
31 PyObject_HEAD
32 int fd;
33 unsigned readable : 1;
34 unsigned writable : 1;
35 int seekable : 2; /* -1 means unknown */
36 int closefd : 1;
37 PyObject *weakreflist;
38} PyFileIOObject;
39
40PyTypeObject PyFileIO_Type;
41
42#define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
43
44/* Returns 0 on success, errno (which is < 0) on failure. */
45static int
46internal_close(PyFileIOObject *self)
47{
48 int save_errno = 0;
49 if (self->fd >= 0) {
50 int fd = self->fd;
51 self->fd = -1;
52 Py_BEGIN_ALLOW_THREADS
53 if (close(fd) < 0)
54 save_errno = errno;
55 Py_END_ALLOW_THREADS
56 }
57 return save_errno;
58}
59
60static PyObject *
61fileio_close(PyFileIOObject *self)
62{
63 if (!self->closefd) {
Georg Brandld2094602008-12-05 08:51:30 +000064 self->fd = -1;
Christian Heimes7f39c9f2008-01-25 12:18:43 +000065 Py_RETURN_NONE;
66 }
67 errno = internal_close(self);
68 if (errno < 0) {
69 PyErr_SetFromErrno(PyExc_IOError);
70 return NULL;
71 }
72
73 Py_RETURN_NONE;
74}
75
76static PyObject *
77fileio_new(PyTypeObject *type, PyObject *args, PyObject *kews)
78{
79 PyFileIOObject *self;
80
81 assert(type != NULL && type->tp_alloc != NULL);
82
83 self = (PyFileIOObject *) type->tp_alloc(type, 0);
84 if (self != NULL) {
85 self->fd = -1;
Christian Heimes8efccfd2008-10-30 21:52:43 +000086 self->readable = 0;
87 self->writable = 0;
88 self->seekable = -1;
89 self->closefd = 1;
Christian Heimes7f39c9f2008-01-25 12:18:43 +000090 self->weakreflist = NULL;
91 }
92
93 return (PyObject *) self;
94}
95
96/* On Unix, open will succeed for directories.
97 In Python, there should be no file objects referring to
98 directories, so we need a check. */
99
100static int
Georg Brandl47fe9812009-01-01 15:46:10 +0000101dircheck(PyFileIOObject* self, char *name)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000102{
103#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
104 struct stat buf;
105 if (self->fd < 0)
106 return 0;
107 if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000108 char *msg = strerror(EISDIR);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000109 PyObject *exc;
110 internal_close(self);
111
Georg Brandl47fe9812009-01-01 15:46:10 +0000112 exc = PyObject_CallFunction(PyExc_IOError, "(iss)",
113 EISDIR, msg, name);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000114 PyErr_SetObject(PyExc_IOError, exc);
115 Py_XDECREF(exc);
116 return -1;
117 }
118#endif
119 return 0;
120}
121
122
123static int
124fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
125{
126 PyFileIOObject *self = (PyFileIOObject *) oself;
127 static char *kwlist[] = {"file", "mode", "closefd", NULL};
128 char *name = NULL;
129 char *mode = "r";
130 char *s;
131#ifdef MS_WINDOWS
132 Py_UNICODE *widename = NULL;
133#endif
134 int ret = 0;
135 int rwa = 0, plus = 0, append = 0;
136 int flags = 0;
137 int fd = -1;
138 int closefd = 1;
139
140 assert(PyFileIO_Check(oself));
141 if (self->fd >= 0) {
142 /* Have to close the existing file first. */
143 if (internal_close(self) < 0)
144 return -1;
145 }
146
147 if (PyArg_ParseTupleAndKeywords(args, kwds, "i|si:fileio",
148 kwlist, &fd, &mode, &closefd)) {
149 if (fd < 0) {
150 PyErr_SetString(PyExc_ValueError,
151 "Negative filedescriptor");
152 return -1;
153 }
154 }
155 else {
156 PyErr_Clear();
157
158#ifdef Py_WIN_WIDE_FILENAMES
159 if (GetVersion() < 0x80000000) {
160 /* On NT, so wide API available */
161 PyObject *po;
162 if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:fileio",
163 kwlist, &po, &mode, &closefd)
164 ) {
165 widename = PyUnicode_AS_UNICODE(po);
166 } else {
167 /* Drop the argument parsing error as narrow
168 strings are also valid. */
169 PyErr_Clear();
170 }
171 }
172 if (widename == NULL)
173#endif
174 {
175 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:fileio",
176 kwlist,
177 Py_FileSystemDefaultEncoding,
178 &name, &mode, &closefd))
Neal Norwitz901e4712008-08-24 22:03:05 +0000179 return -1;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000180 }
181 }
182
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000183 s = mode;
184 while (*s) {
185 switch (*s++) {
186 case 'r':
187 if (rwa) {
188 bad_mode:
189 PyErr_SetString(PyExc_ValueError,
190 "Must have exactly one of read/write/append mode");
191 goto error;
192 }
193 rwa = 1;
194 self->readable = 1;
195 break;
196 case 'w':
197 if (rwa)
198 goto bad_mode;
199 rwa = 1;
200 self->writable = 1;
201 flags |= O_CREAT | O_TRUNC;
202 break;
203 case 'a':
204 if (rwa)
205 goto bad_mode;
206 rwa = 1;
207 self->writable = 1;
208 flags |= O_CREAT;
209 append = 1;
210 break;
Georg Brandlfa71a902008-12-05 09:08:28 +0000211 case 'b':
212 break;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000213 case '+':
214 if (plus)
215 goto bad_mode;
216 self->readable = self->writable = 1;
217 plus = 1;
218 break;
219 default:
220 PyErr_Format(PyExc_ValueError,
221 "invalid mode: %.200s", mode);
222 goto error;
223 }
224 }
225
226 if (!rwa)
227 goto bad_mode;
228
229 if (self->readable && self->writable)
230 flags |= O_RDWR;
231 else if (self->readable)
232 flags |= O_RDONLY;
233 else
234 flags |= O_WRONLY;
235
236#ifdef O_BINARY
237 flags |= O_BINARY;
238#endif
239
240#ifdef O_APPEND
241 if (append)
242 flags |= O_APPEND;
243#endif
244
245 if (fd >= 0) {
246 self->fd = fd;
247 self->closefd = closefd;
248 }
249 else {
250 self->closefd = 1;
251 if (!closefd) {
252 PyErr_SetString(PyExc_ValueError,
Georg Brandl4aef7032008-11-07 08:56:27 +0000253 "Cannot use closefd=False with file name");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000254 goto error;
255 }
256
257 Py_BEGIN_ALLOW_THREADS
258 errno = 0;
259#ifdef MS_WINDOWS
260 if (widename != NULL)
261 self->fd = _wopen(widename, flags, 0666);
262 else
263#endif
264 self->fd = open(name, flags, 0666);
265 Py_END_ALLOW_THREADS
Benjamin Petersonf22c26e2008-09-01 14:13:43 +0000266 if (self->fd < 0) {
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000267#ifdef MS_WINDOWS
268 PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename);
269#else
270 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
271#endif
272 goto error;
273 }
Georg Brandl47fe9812009-01-01 15:46:10 +0000274 if(dircheck(self, name) < 0)
Benjamin Petersonf22c26e2008-09-01 14:13:43 +0000275 goto error;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000276 }
277
278 goto done;
279
280 error:
281 ret = -1;
282
283 done:
Neal Norwitz18aa3882008-08-24 05:04:52 +0000284 PyMem_Free(name);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000285 return ret;
286}
287
288static void
289fileio_dealloc(PyFileIOObject *self)
290{
291 if (self->weakreflist != NULL)
292 PyObject_ClearWeakRefs((PyObject *) self);
293
294 if (self->fd >= 0 && self->closefd) {
295 errno = internal_close(self);
296 if (errno < 0) {
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000297 PySys_WriteStderr("close failed: [Errno %d] %s\n",
298 errno, strerror(errno));
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000299 }
300 }
301
302 Py_TYPE(self)->tp_free((PyObject *)self);
303}
304
305static PyObject *
306err_closed(void)
307{
308 PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
309 return NULL;
310}
311
312static PyObject *
313err_mode(char *action)
314{
315 PyErr_Format(PyExc_ValueError, "File not open for %s", action);
316 return NULL;
317}
318
319static PyObject *
320fileio_fileno(PyFileIOObject *self)
321{
322 if (self->fd < 0)
323 return err_closed();
324 return PyInt_FromLong((long) self->fd);
325}
326
327static PyObject *
328fileio_readable(PyFileIOObject *self)
329{
330 if (self->fd < 0)
331 return err_closed();
332 return PyBool_FromLong((long) self->readable);
333}
334
335static PyObject *
336fileio_writable(PyFileIOObject *self)
337{
338 if (self->fd < 0)
339 return err_closed();
340 return PyBool_FromLong((long) self->writable);
341}
342
343static PyObject *
344fileio_seekable(PyFileIOObject *self)
345{
346 if (self->fd < 0)
347 return err_closed();
348 if (self->seekable < 0) {
349 int ret;
350 Py_BEGIN_ALLOW_THREADS
351 ret = lseek(self->fd, 0, SEEK_CUR);
352 Py_END_ALLOW_THREADS
353 if (ret < 0)
354 self->seekable = 0;
355 else
356 self->seekable = 1;
357 }
358 return PyBool_FromLong((long) self->seekable);
359}
360
361static PyObject *
362fileio_readinto(PyFileIOObject *self, PyObject *args)
363{
Martin v. Löwisf91d46a2008-08-12 14:49:50 +0000364 Py_buffer pbuf;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000365 Py_ssize_t n;
366
367 if (self->fd < 0)
368 return err_closed();
369 if (!self->readable)
370 return err_mode("reading");
371
Martin v. Löwisf91d46a2008-08-12 14:49:50 +0000372 if (!PyArg_ParseTuple(args, "w*", &pbuf))
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000373 return NULL;
374
375 Py_BEGIN_ALLOW_THREADS
376 errno = 0;
Martin v. Löwisf91d46a2008-08-12 14:49:50 +0000377 n = read(self->fd, pbuf.buf, pbuf.len);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000378 Py_END_ALLOW_THREADS
Martin v. Löwisf91d46a2008-08-12 14:49:50 +0000379 PyBuffer_Release(&pbuf);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000380 if (n < 0) {
381 if (errno == EAGAIN)
382 Py_RETURN_NONE;
383 PyErr_SetFromErrno(PyExc_IOError);
384 return NULL;
385 }
386
387 return PyLong_FromSsize_t(n);
388}
389
390#define DEFAULT_BUFFER_SIZE (8*1024)
391
392static PyObject *
393fileio_readall(PyFileIOObject *self)
394{
395 PyObject *result;
396 Py_ssize_t total = 0;
397 int n;
398
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000399 result = PyString_FromStringAndSize(NULL, DEFAULT_BUFFER_SIZE);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000400 if (result == NULL)
401 return NULL;
402
403 while (1) {
404 Py_ssize_t newsize = total + DEFAULT_BUFFER_SIZE;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000405 if (PyString_GET_SIZE(result) < newsize) {
406 if (_PyString_Resize(&result, newsize) < 0) {
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000407 if (total == 0) {
408 Py_DECREF(result);
409 return NULL;
410 }
411 PyErr_Clear();
412 break;
413 }
414 }
415 Py_BEGIN_ALLOW_THREADS
416 errno = 0;
417 n = read(self->fd,
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000418 PyString_AS_STRING(result) + total,
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000419 newsize - total);
420 Py_END_ALLOW_THREADS
421 if (n == 0)
422 break;
423 if (n < 0) {
424 if (total > 0)
425 break;
426 if (errno == EAGAIN) {
427 Py_DECREF(result);
428 Py_RETURN_NONE;
429 }
430 Py_DECREF(result);
431 PyErr_SetFromErrno(PyExc_IOError);
432 return NULL;
433 }
434 total += n;
435 }
436
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000437 if (PyString_GET_SIZE(result) > total) {
438 if (_PyString_Resize(&result, total) < 0) {
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000439 /* This should never happen, but just in case */
440 Py_DECREF(result);
441 return NULL;
442 }
443 }
444 return result;
445}
446
447static PyObject *
448fileio_read(PyFileIOObject *self, PyObject *args)
449{
450 char *ptr;
451 Py_ssize_t n;
452 Py_ssize_t size = -1;
453 PyObject *bytes;
454
455 if (self->fd < 0)
456 return err_closed();
457 if (!self->readable)
458 return err_mode("reading");
459
460 if (!PyArg_ParseTuple(args, "|n", &size))
461 return NULL;
462
463 if (size < 0) {
464 return fileio_readall(self);
465 }
466
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000467 bytes = PyString_FromStringAndSize(NULL, size);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000468 if (bytes == NULL)
469 return NULL;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000470 ptr = PyString_AS_STRING(bytes);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000471
472 Py_BEGIN_ALLOW_THREADS
473 errno = 0;
474 n = read(self->fd, ptr, size);
475 Py_END_ALLOW_THREADS
476
477 if (n < 0) {
478 if (errno == EAGAIN)
479 Py_RETURN_NONE;
480 PyErr_SetFromErrno(PyExc_IOError);
481 return NULL;
482 }
483
484 if (n != size) {
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000485 if (_PyString_Resize(&bytes, n) < 0) {
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000486 Py_DECREF(bytes);
487 return NULL;
488 }
489 }
490
491 return (PyObject *) bytes;
492}
493
494static PyObject *
495fileio_write(PyFileIOObject *self, PyObject *args)
496{
Martin v. Löwisf91d46a2008-08-12 14:49:50 +0000497 Py_buffer pbuf;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000498 Py_ssize_t n;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000499
500 if (self->fd < 0)
501 return err_closed();
502 if (!self->writable)
503 return err_mode("writing");
504
Martin v. Löwisf91d46a2008-08-12 14:49:50 +0000505 if (!PyArg_ParseTuple(args, "s*", &pbuf))
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000506 return NULL;
507
508 Py_BEGIN_ALLOW_THREADS
509 errno = 0;
Martin v. Löwisf91d46a2008-08-12 14:49:50 +0000510 n = write(self->fd, pbuf.buf, pbuf.len);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000511 Py_END_ALLOW_THREADS
512
Martin v. Löwisf91d46a2008-08-12 14:49:50 +0000513 PyBuffer_Release(&pbuf);
514
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000515 if (n < 0) {
516 if (errno == EAGAIN)
517 Py_RETURN_NONE;
518 PyErr_SetFromErrno(PyExc_IOError);
519 return NULL;
520 }
521
522 return PyLong_FromSsize_t(n);
523}
524
525/* XXX Windows support below is likely incomplete */
526
527#if defined(MS_WIN64) || defined(MS_WINDOWS)
528typedef PY_LONG_LONG Py_off_t;
529#else
530typedef off_t Py_off_t;
531#endif
532
533/* Cribbed from posix_lseek() */
534static PyObject *
535portable_lseek(int fd, PyObject *posobj, int whence)
536{
537 Py_off_t pos, res;
538
539#ifdef SEEK_SET
540 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
541 switch (whence) {
542#if SEEK_SET != 0
543 case 0: whence = SEEK_SET; break;
544#endif
545#if SEEK_CUR != 1
546 case 1: whence = SEEK_CUR; break;
547#endif
548#if SEEL_END != 2
549 case 2: whence = SEEK_END; break;
550#endif
551 }
552#endif /* SEEK_SET */
553
554 if (posobj == NULL)
555 pos = 0;
556 else {
557 if(PyFloat_Check(posobj)) {
558 PyErr_SetString(PyExc_TypeError, "an integer is required");
559 return NULL;
560 }
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000561#if defined(HAVE_LARGEFILE_SUPPORT)
562 pos = PyLong_AsLongLong(posobj);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000563#else
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000564 pos = PyLong_AsLong(posobj);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000565#endif
566 if (PyErr_Occurred())
567 return NULL;
568 }
569
570 Py_BEGIN_ALLOW_THREADS
571#if defined(MS_WIN64) || defined(MS_WINDOWS)
572 res = _lseeki64(fd, pos, whence);
573#else
574 res = lseek(fd, pos, whence);
575#endif
576 Py_END_ALLOW_THREADS
577 if (res < 0)
578 return PyErr_SetFromErrno(PyExc_IOError);
579
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000580#if defined(HAVE_LARGEFILE_SUPPORT)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000581 return PyLong_FromLongLong(res);
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000582#else
583 return PyLong_FromLong(res);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000584#endif
585}
586
587static PyObject *
588fileio_seek(PyFileIOObject *self, PyObject *args)
589{
590 PyObject *posobj;
591 int whence = 0;
592
593 if (self->fd < 0)
594 return err_closed();
595
596 if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))
597 return NULL;
598
599 return portable_lseek(self->fd, posobj, whence);
600}
601
602static PyObject *
603fileio_tell(PyFileIOObject *self, PyObject *args)
604{
605 if (self->fd < 0)
606 return err_closed();
607
608 return portable_lseek(self->fd, NULL, 1);
609}
610
611#ifdef HAVE_FTRUNCATE
612static PyObject *
613fileio_truncate(PyFileIOObject *self, PyObject *args)
614{
615 PyObject *posobj = NULL;
616 Py_off_t pos;
617 int ret;
618 int fd;
619
620 fd = self->fd;
621 if (fd < 0)
622 return err_closed();
623 if (!self->writable)
624 return err_mode("writing");
625
626 if (!PyArg_ParseTuple(args, "|O", &posobj))
627 return NULL;
628
629 if (posobj == Py_None || posobj == NULL) {
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000630 /* Get the current position. */
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000631 posobj = portable_lseek(fd, NULL, 1);
632 if (posobj == NULL)
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000633 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000634 }
635 else {
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000636 /* Move to the position to be truncated. */
637 posobj = portable_lseek(fd, posobj, 0);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000638 }
639
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000640#if defined(HAVE_LARGEFILE_SUPPORT)
641 pos = PyLong_AsLongLong(posobj);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000642#else
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000643 pos = PyLong_AsLong(posobj);
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000644#endif
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000645 if (PyErr_Occurred())
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000646 return NULL;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000647
648#ifdef MS_WINDOWS
649 /* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
650 so don't even try using it. */
651 {
652 HANDLE hFile;
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000653
654 /* Truncate. Note that this may grow the file! */
655 Py_BEGIN_ALLOW_THREADS
656 errno = 0;
657 hFile = (HANDLE)_get_osfhandle(fd);
658 ret = hFile == (HANDLE)-1;
659 if (ret == 0) {
660 ret = SetEndOfFile(hFile) == 0;
661 if (ret)
662 errno = EACCES;
663 }
664 Py_END_ALLOW_THREADS
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000665 }
666#else
667 Py_BEGIN_ALLOW_THREADS
668 errno = 0;
669 ret = ftruncate(fd, pos);
670 Py_END_ALLOW_THREADS
671#endif /* !MS_WINDOWS */
672
673 if (ret != 0) {
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000674 PyErr_SetFromErrno(PyExc_IOError);
675 return NULL;
676 }
677
678 return posobj;
679}
680#endif
681
682static char *
683mode_string(PyFileIOObject *self)
684{
685 if (self->readable) {
686 if (self->writable)
Georg Brandlfa71a902008-12-05 09:08:28 +0000687 return "rb+";
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000688 else
Georg Brandlfa71a902008-12-05 09:08:28 +0000689 return "rb";
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000690 }
691 else
Georg Brandlfa71a902008-12-05 09:08:28 +0000692 return "wb";
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000693}
694
695static PyObject *
696fileio_repr(PyFileIOObject *self)
697{
698 if (self->fd < 0)
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000699 return PyString_FromFormat("_fileio._FileIO(-1)");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000700
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000701 return PyString_FromFormat("_fileio._FileIO(%d, '%s')",
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000702 self->fd, mode_string(self));
703}
704
705static PyObject *
706fileio_isatty(PyFileIOObject *self)
707{
708 long res;
709
710 if (self->fd < 0)
711 return err_closed();
712 Py_BEGIN_ALLOW_THREADS
713 res = isatty(self->fd);
714 Py_END_ALLOW_THREADS
715 return PyBool_FromLong(res);
716}
717
718
719PyDoc_STRVAR(fileio_doc,
720"file(name: str[, mode: str]) -> file IO object\n"
721"\n"
722"Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n"
723"writing or appending. The file will be created if it doesn't exist\n"
724"when opened for writing or appending; it will be truncated when\n"
725"opened for writing. Add a '+' to the mode to allow simultaneous\n"
726"reading and writing.");
727
728PyDoc_STRVAR(read_doc,
729"read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"
730"\n"
731"Only makes one system call, so less data may be returned than requested\n"
732"In non-blocking mode, returns None if no data is available.\n"
733"On end-of-file, returns ''.");
734
735PyDoc_STRVAR(readall_doc,
736"readall() -> bytes. read all data from the file, returned as bytes.\n"
737"\n"
738"In non-blocking mode, returns as much as is immediately available,\n"
739"or None if no data is available. On end-of-file, returns ''.");
740
741PyDoc_STRVAR(write_doc,
742"write(b: bytes) -> int. Write bytes b to file, return number written.\n"
743"\n"
744"Only makes one system call, so not all of the data may be written.\n"
745"The number of bytes actually written is returned.");
746
747PyDoc_STRVAR(fileno_doc,
748"fileno() -> int. \"file descriptor\".\n"
749"\n"
750"This is needed for lower-level file interfaces, such the fcntl module.");
751
752PyDoc_STRVAR(seek_doc,
753"seek(offset: int[, whence: int]) -> None. Move to new file position.\n"
754"\n"
755"Argument offset is a byte count. Optional argument whence defaults to\n"
756"0 (offset from start of file, offset should be >= 0); other values are 1\n"
757"(move relative to current position, positive or negative), and 2 (move\n"
758"relative to end of file, usually negative, although many platforms allow\n"
759"seeking beyond the end of a file)."
760"\n"
761"Note that not all file objects are seekable.");
762
763#ifdef HAVE_FTRUNCATE
764PyDoc_STRVAR(truncate_doc,
765"truncate([size: int]) -> None. Truncate the file to at most size bytes.\n"
766"\n"
Alexandre Vassalotti1aed6242008-05-09 21:49:43 +0000767"Size defaults to the current file position, as returned by tell()."
768"The current file position is changed to the value of size.");
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000769#endif
770
771PyDoc_STRVAR(tell_doc,
772"tell() -> int. Current file position");
773
774PyDoc_STRVAR(readinto_doc,
775"readinto() -> Undocumented. Don't use this; it may go away.");
776
777PyDoc_STRVAR(close_doc,
778"close() -> None. Close the file.\n"
779"\n"
780"A closed file cannot be used for further I/O operations. close() may be\n"
781"called more than once without error. Changes the fileno to -1.");
782
783PyDoc_STRVAR(isatty_doc,
784"isatty() -> bool. True if the file is connected to a tty device.");
785
786PyDoc_STRVAR(seekable_doc,
787"seekable() -> bool. True if file supports random-access.");
788
789PyDoc_STRVAR(readable_doc,
790"readable() -> bool. True if file was opened in a read mode.");
791
792PyDoc_STRVAR(writable_doc,
793"writable() -> bool. True if file was opened in a write mode.");
794
795static PyMethodDef fileio_methods[] = {
796 {"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc},
797 {"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc},
798 {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},
799 {"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc},
800 {"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc},
801 {"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc},
802#ifdef HAVE_FTRUNCATE
803 {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},
804#endif
805 {"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc},
806 {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc},
807 {"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc},
808 {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc},
809 {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc},
810 {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc},
811 {NULL, NULL} /* sentinel */
812};
813
814/* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
815
816static PyObject *
817get_closed(PyFileIOObject *self, void *closure)
818{
819 return PyBool_FromLong((long)(self->fd < 0));
820}
821
822static PyObject *
Georg Brandld2094602008-12-05 08:51:30 +0000823get_closefd(PyFileIOObject *self, void *closure)
824{
825 return PyBool_FromLong((long)(self->closefd));
826}
827
828static PyObject *
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000829get_mode(PyFileIOObject *self, void *closure)
830{
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000831 return PyString_FromString(mode_string(self));
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000832}
833
834static PyGetSetDef fileio_getsetlist[] = {
835 {"closed", (getter)get_closed, NULL, "True if the file is closed"},
Georg Brandld2094602008-12-05 08:51:30 +0000836 {"closefd", (getter)get_closefd, NULL,
837 "True if the file descriptor will be closed"},
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000838 {"mode", (getter)get_mode, NULL, "String giving the file mode"},
839 {0},
840};
841
842PyTypeObject PyFileIO_Type = {
Hirokazu Yamamoto09979a12008-09-23 16:11:09 +0000843 PyVarObject_HEAD_INIT(NULL, 0)
Christian Heimes7f39c9f2008-01-25 12:18:43 +0000844 "_FileIO",
845 sizeof(PyFileIOObject),
846 0,
847 (destructor)fileio_dealloc, /* tp_dealloc */
848 0, /* tp_print */
849 0, /* tp_getattr */
850 0, /* tp_setattr */
851 0, /* tp_compare */
852 (reprfunc)fileio_repr, /* tp_repr */
853 0, /* tp_as_number */
854 0, /* tp_as_sequence */
855 0, /* tp_as_mapping */
856 0, /* tp_hash */
857 0, /* tp_call */
858 0, /* tp_str */
859 PyObject_GenericGetAttr, /* tp_getattro */
860 0, /* tp_setattro */
861 0, /* tp_as_buffer */
862 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
863 fileio_doc, /* tp_doc */
864 0, /* tp_traverse */
865 0, /* tp_clear */
866 0, /* tp_richcompare */
867 offsetof(PyFileIOObject, weakreflist), /* tp_weaklistoffset */
868 0, /* tp_iter */
869 0, /* tp_iternext */
870 fileio_methods, /* tp_methods */
871 0, /* tp_members */
872 fileio_getsetlist, /* tp_getset */
873 0, /* tp_base */
874 0, /* tp_dict */
875 0, /* tp_descr_get */
876 0, /* tp_descr_set */
877 0, /* tp_dictoffset */
878 fileio_init, /* tp_init */
879 PyType_GenericAlloc, /* tp_alloc */
880 fileio_new, /* tp_new */
881 PyObject_Del, /* tp_free */
882};
883
884static PyMethodDef module_methods[] = {
885 {NULL, NULL}
886};
887
888PyMODINIT_FUNC
889init_fileio(void)
890{
891 PyObject *m; /* a module object */
892
893 m = Py_InitModule3("_fileio", module_methods,
894 "Fast implementation of io.FileIO.");
895 if (m == NULL)
896 return;
897 if (PyType_Ready(&PyFileIO_Type) < 0)
898 return;
899 Py_INCREF(&PyFileIO_Type);
900 PyModule_AddObject(m, "_FileIO", (PyObject *) &PyFileIO_Type);
901}