]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Python/Python-2.7.2/Modules/_io/fileio.c
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Modules / _io / fileio.c
CommitLineData
4710c53d 1/* Author: Daniel Stutzbach */\r
2\r
3#define PY_SSIZE_T_CLEAN\r
4#include "Python.h"\r
5#ifdef HAVE_SYS_TYPES_H\r
6#include <sys/types.h>\r
7#endif\r
8#ifdef HAVE_SYS_STAT_H\r
9#include <sys/stat.h>\r
10#endif\r
11#ifdef HAVE_FCNTL_H\r
12#include <fcntl.h>\r
13#endif\r
14#include <stddef.h> /* For offsetof */\r
15#include "_iomodule.h"\r
16\r
17/*\r
18 * Known likely problems:\r
19 *\r
20 * - Files larger then 2**32-1\r
21 * - Files with unicode filenames\r
22 * - Passing numbers greater than 2**32-1 when an integer is expected\r
23 * - Making it work on Windows and other oddball platforms\r
24 *\r
25 * To Do:\r
26 *\r
27 * - autoconfify header file inclusion\r
28 */\r
29\r
30#ifdef MS_WINDOWS\r
31/* can simulate truncate with Win32 API functions; see file_truncate */\r
32#define HAVE_FTRUNCATE\r
33#define WIN32_LEAN_AND_MEAN\r
34#include <windows.h>\r
35#endif\r
36\r
37#if BUFSIZ < (8*1024)\r
38#define SMALLCHUNK (8*1024)\r
39#elif (BUFSIZ >= (2 << 25))\r
40#error "unreasonable BUFSIZ > 64MB defined"\r
41#else\r
42#define SMALLCHUNK BUFSIZ\r
43#endif\r
44\r
45#if SIZEOF_INT < 4\r
46#define BIGCHUNK (512 * 32)\r
47#else\r
48#define BIGCHUNK (512 * 1024)\r
49#endif\r
50\r
51typedef struct {\r
52 PyObject_HEAD\r
53 int fd;\r
54 unsigned int readable : 1;\r
55 unsigned int writable : 1;\r
56 signed int seekable : 2; /* -1 means unknown */\r
57 unsigned int closefd : 1;\r
58 PyObject *weakreflist;\r
59 PyObject *dict;\r
60} fileio;\r
61\r
62PyTypeObject PyFileIO_Type;\r
63\r
64#define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))\r
65\r
66int\r
67_PyFileIO_closed(PyObject *self)\r
68{\r
69 return ((fileio *)self)->fd < 0;\r
70}\r
71\r
72static PyObject *\r
73portable_lseek(int fd, PyObject *posobj, int whence);\r
74\r
75static PyObject *portable_lseek(int fd, PyObject *posobj, int whence);\r
76\r
77/* Returns 0 on success, -1 with exception set on failure. */\r
78static int\r
79internal_close(fileio *self)\r
80{\r
81 int err = 0;\r
82 int save_errno = 0;\r
83 if (self->fd >= 0) {\r
84 int fd = self->fd;\r
85 self->fd = -1;\r
86 /* fd is accessible and someone else may have closed it */\r
87 if (_PyVerify_fd(fd)) {\r
88 Py_BEGIN_ALLOW_THREADS\r
89 err = close(fd);\r
90 if (err < 0)\r
91 save_errno = errno;\r
92 Py_END_ALLOW_THREADS\r
93 } else {\r
94 save_errno = errno;\r
95 err = -1;\r
96 }\r
97 }\r
98 if (err < 0) {\r
99 errno = save_errno;\r
100 PyErr_SetFromErrno(PyExc_IOError);\r
101 return -1;\r
102 }\r
103 return 0;\r
104}\r
105\r
106static PyObject *\r
107fileio_close(fileio *self)\r
108{\r
109 if (!self->closefd) {\r
110 self->fd = -1;\r
111 Py_RETURN_NONE;\r
112 }\r
113 errno = internal_close(self);\r
114 if (errno < 0)\r
115 return NULL;\r
116\r
117 return PyObject_CallMethod((PyObject*)&PyRawIOBase_Type,\r
118 "close", "O", self);\r
119}\r
120\r
121static PyObject *\r
122fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\r
123{\r
124 fileio *self;\r
125\r
126 assert(type != NULL && type->tp_alloc != NULL);\r
127\r
128 self = (fileio *) type->tp_alloc(type, 0);\r
129 if (self != NULL) {\r
130 self->fd = -1;\r
131 self->readable = 0;\r
132 self->writable = 0;\r
133 self->seekable = -1;\r
134 self->closefd = 1;\r
135 self->weakreflist = NULL;\r
136 }\r
137\r
138 return (PyObject *) self;\r
139}\r
140\r
141/* On Unix, open will succeed for directories.\r
142 In Python, there should be no file objects referring to\r
143 directories, so we need a check. */\r
144\r
145static int\r
146dircheck(fileio* self, const char *name)\r
147{\r
148#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)\r
149 struct stat buf;\r
150 if (self->fd < 0)\r
151 return 0;\r
152 if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {\r
153 char *msg = strerror(EISDIR);\r
154 PyObject *exc;\r
155 if (internal_close(self))\r
156 return -1;\r
157\r
158 exc = PyObject_CallFunction(PyExc_IOError, "(iss)",\r
159 EISDIR, msg, name);\r
160 PyErr_SetObject(PyExc_IOError, exc);\r
161 Py_XDECREF(exc);\r
162 return -1;\r
163 }\r
164#endif\r
165 return 0;\r
166}\r
167\r
168static int\r
169check_fd(int fd)\r
170{\r
171#if defined(HAVE_FSTAT)\r
172 struct stat buf;\r
173 if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) {\r
174 PyObject *exc;\r
175 char *msg = strerror(EBADF);\r
176 exc = PyObject_CallFunction(PyExc_OSError, "(is)",\r
177 EBADF, msg);\r
178 PyErr_SetObject(PyExc_OSError, exc);\r
179 Py_XDECREF(exc);\r
180 return -1;\r
181 }\r
182#endif\r
183 return 0;\r
184}\r
185\r
186\r
187static int\r
188fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)\r
189{\r
190 fileio *self = (fileio *) oself;\r
191 static char *kwlist[] = {"file", "mode", "closefd", NULL};\r
192 const char *name = NULL;\r
193 PyObject *nameobj, *stringobj = NULL;\r
194 char *mode = "r";\r
195 char *s;\r
196#ifdef MS_WINDOWS\r
197 Py_UNICODE *widename = NULL;\r
198#endif\r
199 int ret = 0;\r
200 int rwa = 0, plus = 0, append = 0;\r
201 int flags = 0;\r
202 int fd = -1;\r
203 int closefd = 1;\r
204\r
205 assert(PyFileIO_Check(oself));\r
206 if (self->fd >= 0) {\r
207 /* Have to close the existing file first. */\r
208 if (internal_close(self) < 0)\r
209 return -1;\r
210 }\r
211\r
212 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:fileio",\r
213 kwlist, &nameobj, &mode, &closefd))\r
214 return -1;\r
215\r
216 if (PyFloat_Check(nameobj)) {\r
217 PyErr_SetString(PyExc_TypeError,\r
218 "integer argument expected, got float");\r
219 return -1;\r
220 }\r
221\r
222 fd = PyLong_AsLong(nameobj);\r
223 if (fd < 0) {\r
224 if (!PyErr_Occurred()) {\r
225 PyErr_SetString(PyExc_ValueError,\r
226 "Negative filedescriptor");\r
227 return -1;\r
228 }\r
229 PyErr_Clear();\r
230 }\r
231\r
232#ifdef MS_WINDOWS\r
233 if (PyUnicode_Check(nameobj))\r
234 widename = PyUnicode_AS_UNICODE(nameobj);\r
235 if (widename == NULL)\r
236#endif\r
237 if (fd < 0)\r
238 {\r
239 if (PyBytes_Check(nameobj) || PyByteArray_Check(nameobj)) {\r
240 Py_ssize_t namelen;\r
241 if (PyObject_AsCharBuffer(nameobj, &name, &namelen) < 0)\r
242 return -1;\r
243 }\r
244 else {\r
245 PyObject *u = PyUnicode_FromObject(nameobj);\r
246\r
247 if (u == NULL)\r
248 return -1;\r
249\r
250 stringobj = PyUnicode_AsEncodedString(\r
251 u, Py_FileSystemDefaultEncoding, NULL);\r
252 Py_DECREF(u);\r
253 if (stringobj == NULL)\r
254 return -1;\r
255 if (!PyBytes_Check(stringobj)) {\r
256 PyErr_SetString(PyExc_TypeError,\r
257 "encoder failed to return bytes");\r
258 goto error;\r
259 }\r
260 name = PyBytes_AS_STRING(stringobj);\r
261 }\r
262 }\r
263\r
264 s = mode;\r
265 while (*s) {\r
266 switch (*s++) {\r
267 case 'r':\r
268 if (rwa) {\r
269 bad_mode:\r
270 PyErr_SetString(PyExc_ValueError,\r
271 "Must have exactly one of read/write/append "\r
272 "mode and at most one plus");\r
273 goto error;\r
274 }\r
275 rwa = 1;\r
276 self->readable = 1;\r
277 break;\r
278 case 'w':\r
279 if (rwa)\r
280 goto bad_mode;\r
281 rwa = 1;\r
282 self->writable = 1;\r
283 flags |= O_CREAT | O_TRUNC;\r
284 break;\r
285 case 'a':\r
286 if (rwa)\r
287 goto bad_mode;\r
288 rwa = 1;\r
289 self->writable = 1;\r
290 flags |= O_CREAT;\r
291 append = 1;\r
292 break;\r
293 case 'b':\r
294 break;\r
295 case '+':\r
296 if (plus)\r
297 goto bad_mode;\r
298 self->readable = self->writable = 1;\r
299 plus = 1;\r
300 break;\r
301 default:\r
302 PyErr_Format(PyExc_ValueError,\r
303 "invalid mode: %.200s", mode);\r
304 goto error;\r
305 }\r
306 }\r
307\r
308 if (!rwa)\r
309 goto bad_mode;\r
310\r
311 if (self->readable && self->writable)\r
312 flags |= O_RDWR;\r
313 else if (self->readable)\r
314 flags |= O_RDONLY;\r
315 else\r
316 flags |= O_WRONLY;\r
317\r
318#ifdef O_BINARY\r
319 flags |= O_BINARY;\r
320#endif\r
321\r
322#ifdef O_APPEND\r
323 if (append)\r
324 flags |= O_APPEND;\r
325#endif\r
326\r
327 if (fd >= 0) {\r
328 if (check_fd(fd))\r
329 goto error;\r
330 self->fd = fd;\r
331 self->closefd = closefd;\r
332 }\r
333 else {\r
334 self->closefd = 1;\r
335 if (!closefd) {\r
336 PyErr_SetString(PyExc_ValueError,\r
337 "Cannot use closefd=False with file name");\r
338 goto error;\r
339 }\r
340\r
341 Py_BEGIN_ALLOW_THREADS\r
342 errno = 0;\r
343#ifdef MS_WINDOWS\r
344 if (widename != NULL)\r
345 self->fd = _wopen(widename, flags, 0666);\r
346 else\r
347#endif\r
348 self->fd = open(name, flags, 0666);\r
349 Py_END_ALLOW_THREADS\r
350 if (self->fd < 0) {\r
351#ifdef MS_WINDOWS\r
352 if (widename != NULL)\r
353 PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename);\r
354 else\r
355#endif\r
356 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);\r
357 goto error;\r
358 }\r
359 if(dircheck(self, name) < 0)\r
360 goto error;\r
361 }\r
362\r
363 if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0)\r
364 goto error;\r
365\r
366 if (append) {\r
367 /* For consistent behaviour, we explicitly seek to the\r
368 end of file (otherwise, it might be done only on the\r
369 first write()). */\r
370 PyObject *pos = portable_lseek(self->fd, NULL, 2);\r
371 if (pos == NULL) {\r
372 if (closefd) {\r
373 close(self->fd);\r
374 self->fd = -1;\r
375 }\r
376 goto error;\r
377 }\r
378 Py_DECREF(pos);\r
379 }\r
380\r
381 goto done;\r
382\r
383 error:\r
384 ret = -1;\r
385\r
386 done:\r
387 Py_CLEAR(stringobj);\r
388 return ret;\r
389}\r
390\r
391static int\r
392fileio_traverse(fileio *self, visitproc visit, void *arg)\r
393{\r
394 Py_VISIT(self->dict);\r
395 return 0;\r
396}\r
397\r
398static int\r
399fileio_clear(fileio *self)\r
400{\r
401 Py_CLEAR(self->dict);\r
402 return 0;\r
403}\r
404\r
405static void\r
406fileio_dealloc(fileio *self)\r
407{\r
408 if (_PyIOBase_finalize((PyObject *) self) < 0)\r
409 return;\r
410 _PyObject_GC_UNTRACK(self);\r
411 if (self->weakreflist != NULL)\r
412 PyObject_ClearWeakRefs((PyObject *) self);\r
413 Py_CLEAR(self->dict);\r
414 Py_TYPE(self)->tp_free((PyObject *)self);\r
415}\r
416\r
417static PyObject *\r
418err_closed(void)\r
419{\r
420 PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");\r
421 return NULL;\r
422}\r
423\r
424static PyObject *\r
425err_mode(char *action)\r
426{\r
427 PyErr_Format(PyExc_ValueError, "File not open for %s", action);\r
428 return NULL;\r
429}\r
430\r
431static PyObject *\r
432fileio_fileno(fileio *self)\r
433{\r
434 if (self->fd < 0)\r
435 return err_closed();\r
436 return PyInt_FromLong((long) self->fd);\r
437}\r
438\r
439static PyObject *\r
440fileio_readable(fileio *self)\r
441{\r
442 if (self->fd < 0)\r
443 return err_closed();\r
444 return PyBool_FromLong((long) self->readable);\r
445}\r
446\r
447static PyObject *\r
448fileio_writable(fileio *self)\r
449{\r
450 if (self->fd < 0)\r
451 return err_closed();\r
452 return PyBool_FromLong((long) self->writable);\r
453}\r
454\r
455static PyObject *\r
456fileio_seekable(fileio *self)\r
457{\r
458 if (self->fd < 0)\r
459 return err_closed();\r
460 if (self->seekable < 0) {\r
461 PyObject *pos = portable_lseek(self->fd, NULL, SEEK_CUR);\r
462 if (pos == NULL) {\r
463 PyErr_Clear();\r
464 self->seekable = 0;\r
465 } else {\r
466 Py_DECREF(pos);\r
467 self->seekable = 1;\r
468 }\r
469 }\r
470 return PyBool_FromLong((long) self->seekable);\r
471}\r
472\r
473static PyObject *\r
474fileio_readinto(fileio *self, PyObject *args)\r
475{\r
476 Py_buffer pbuf;\r
477 Py_ssize_t n;\r
478\r
479 if (self->fd < 0)\r
480 return err_closed();\r
481 if (!self->readable)\r
482 return err_mode("reading");\r
483\r
484 if (!PyArg_ParseTuple(args, "w*", &pbuf))\r
485 return NULL;\r
486\r
487 if (_PyVerify_fd(self->fd)) {\r
488 Py_BEGIN_ALLOW_THREADS\r
489 errno = 0;\r
490 n = read(self->fd, pbuf.buf, pbuf.len);\r
491 Py_END_ALLOW_THREADS\r
492 } else\r
493 n = -1;\r
494 PyBuffer_Release(&pbuf);\r
495 if (n < 0) {\r
496 if (errno == EAGAIN)\r
497 Py_RETURN_NONE;\r
498 PyErr_SetFromErrno(PyExc_IOError);\r
499 return NULL;\r
500 }\r
501\r
502 return PyLong_FromSsize_t(n);\r
503}\r
504\r
505static size_t\r
506new_buffersize(fileio *self, size_t currentsize)\r
507{\r
508#ifdef HAVE_FSTAT\r
509 off_t pos, end;\r
510 struct stat st;\r
511 if (fstat(self->fd, &st) == 0) {\r
512 end = st.st_size;\r
513 pos = lseek(self->fd, 0L, SEEK_CUR);\r
514 /* Files claiming a size smaller than SMALLCHUNK may\r
515 actually be streaming pseudo-files. In this case, we\r
516 apply the more aggressive algorithm below.\r
517 */\r
518 if (end >= SMALLCHUNK && end >= pos && pos >= 0) {\r
519 /* Add 1 so if the file were to grow we'd notice. */\r
520 return currentsize + end - pos + 1;\r
521 }\r
522 }\r
523#endif\r
524 if (currentsize > SMALLCHUNK) {\r
525 /* Keep doubling until we reach BIGCHUNK;\r
526 then keep adding BIGCHUNK. */\r
527 if (currentsize <= BIGCHUNK)\r
528 return currentsize + currentsize;\r
529 else\r
530 return currentsize + BIGCHUNK;\r
531 }\r
532 return currentsize + SMALLCHUNK;\r
533}\r
534\r
535static PyObject *\r
536fileio_readall(fileio *self)\r
537{\r
538 PyObject *result;\r
539 Py_ssize_t total = 0;\r
540 int n;\r
541\r
542 if (self->fd < 0)\r
543 return err_closed();\r
544 if (!_PyVerify_fd(self->fd))\r
545 return PyErr_SetFromErrno(PyExc_IOError);\r
546\r
547 result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);\r
548 if (result == NULL)\r
549 return NULL;\r
550\r
551 while (1) {\r
552 size_t newsize = new_buffersize(self, total);\r
553 if (newsize > PY_SSIZE_T_MAX || newsize <= 0) {\r
554 PyErr_SetString(PyExc_OverflowError,\r
555 "unbounded read returned more bytes "\r
556 "than a Python string can hold ");\r
557 Py_DECREF(result);\r
558 return NULL;\r
559 }\r
560\r
561 if (PyBytes_GET_SIZE(result) < (Py_ssize_t)newsize) {\r
562 if (_PyBytes_Resize(&result, newsize) < 0) {\r
563 if (total == 0) {\r
564 Py_DECREF(result);\r
565 return NULL;\r
566 }\r
567 PyErr_Clear();\r
568 break;\r
569 }\r
570 }\r
571 Py_BEGIN_ALLOW_THREADS\r
572 errno = 0;\r
573 n = read(self->fd,\r
574 PyBytes_AS_STRING(result) + total,\r
575 newsize - total);\r
576 Py_END_ALLOW_THREADS\r
577 if (n == 0)\r
578 break;\r
579 if (n < 0) {\r
580 if (total > 0)\r
581 break;\r
582 if (errno == EAGAIN) {\r
583 Py_DECREF(result);\r
584 Py_RETURN_NONE;\r
585 }\r
586 Py_DECREF(result);\r
587 PyErr_SetFromErrno(PyExc_IOError);\r
588 return NULL;\r
589 }\r
590 total += n;\r
591 }\r
592\r
593 if (PyBytes_GET_SIZE(result) > total) {\r
594 if (_PyBytes_Resize(&result, total) < 0) {\r
595 /* This should never happen, but just in case */\r
596 Py_DECREF(result);\r
597 return NULL;\r
598 }\r
599 }\r
600 return result;\r
601}\r
602\r
603static PyObject *\r
604fileio_read(fileio *self, PyObject *args)\r
605{\r
606 char *ptr;\r
607 Py_ssize_t n;\r
608 Py_ssize_t size = -1;\r
609 PyObject *bytes;\r
610\r
611 if (self->fd < 0)\r
612 return err_closed();\r
613 if (!self->readable)\r
614 return err_mode("reading");\r
615\r
616 if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size))\r
617 return NULL;\r
618\r
619 if (size < 0) {\r
620 return fileio_readall(self);\r
621 }\r
622\r
623 bytes = PyBytes_FromStringAndSize(NULL, size);\r
624 if (bytes == NULL)\r
625 return NULL;\r
626 ptr = PyBytes_AS_STRING(bytes);\r
627\r
628 if (_PyVerify_fd(self->fd)) {\r
629 Py_BEGIN_ALLOW_THREADS\r
630 errno = 0;\r
631 n = read(self->fd, ptr, size);\r
632 Py_END_ALLOW_THREADS\r
633 } else\r
634 n = -1;\r
635\r
636 if (n < 0) {\r
637 Py_DECREF(bytes);\r
638 if (errno == EAGAIN)\r
639 Py_RETURN_NONE;\r
640 PyErr_SetFromErrno(PyExc_IOError);\r
641 return NULL;\r
642 }\r
643\r
644 if (n != size) {\r
645 if (_PyBytes_Resize(&bytes, n) < 0) {\r
646 Py_DECREF(bytes);\r
647 return NULL;\r
648 }\r
649 }\r
650\r
651 return (PyObject *) bytes;\r
652}\r
653\r
654static PyObject *\r
655fileio_write(fileio *self, PyObject *args)\r
656{\r
657 Py_buffer pbuf;\r
658 Py_ssize_t n;\r
659\r
660 if (self->fd < 0)\r
661 return err_closed();\r
662 if (!self->writable)\r
663 return err_mode("writing");\r
664\r
665 if (!PyArg_ParseTuple(args, "s*", &pbuf))\r
666 return NULL;\r
667\r
668 if (_PyVerify_fd(self->fd)) {\r
669 Py_BEGIN_ALLOW_THREADS\r
670 errno = 0;\r
671 n = write(self->fd, pbuf.buf, pbuf.len);\r
672 Py_END_ALLOW_THREADS\r
673 } else\r
674 n = -1;\r
675\r
676 PyBuffer_Release(&pbuf);\r
677\r
678 if (n < 0) {\r
679 if (errno == EAGAIN)\r
680 Py_RETURN_NONE;\r
681 PyErr_SetFromErrno(PyExc_IOError);\r
682 return NULL;\r
683 }\r
684\r
685 return PyLong_FromSsize_t(n);\r
686}\r
687\r
688/* XXX Windows support below is likely incomplete */\r
689\r
690/* Cribbed from posix_lseek() */\r
691static PyObject *\r
692portable_lseek(int fd, PyObject *posobj, int whence)\r
693{\r
694 Py_off_t pos, res;\r
695\r
696#ifdef SEEK_SET\r
697 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */\r
698 switch (whence) {\r
699#if SEEK_SET != 0\r
700 case 0: whence = SEEK_SET; break;\r
701#endif\r
702#if SEEK_CUR != 1\r
703 case 1: whence = SEEK_CUR; break;\r
704#endif\r
705#if SEEK_END != 2\r
706 case 2: whence = SEEK_END; break;\r
707#endif\r
708 }\r
709#endif /* SEEK_SET */\r
710\r
711 if (posobj == NULL)\r
712 pos = 0;\r
713 else {\r
714 if(PyFloat_Check(posobj)) {\r
715 PyErr_SetString(PyExc_TypeError, "an integer is required");\r
716 return NULL;\r
717 }\r
718#if defined(HAVE_LARGEFILE_SUPPORT)\r
719 pos = PyLong_AsLongLong(posobj);\r
720#else\r
721 pos = PyLong_AsLong(posobj);\r
722#endif\r
723 if (PyErr_Occurred())\r
724 return NULL;\r
725 }\r
726\r
727 if (_PyVerify_fd(fd)) {\r
728 Py_BEGIN_ALLOW_THREADS\r
729#if defined(MS_WIN64) || defined(MS_WINDOWS)\r
730 res = _lseeki64(fd, pos, whence);\r
731#else\r
732 res = lseek(fd, pos, whence);\r
733#endif\r
734 Py_END_ALLOW_THREADS\r
735 } else\r
736 res = -1;\r
737 if (res < 0)\r
738 return PyErr_SetFromErrno(PyExc_IOError);\r
739\r
740#if defined(HAVE_LARGEFILE_SUPPORT)\r
741 return PyLong_FromLongLong(res);\r
742#else\r
743 return PyLong_FromLong(res);\r
744#endif\r
745}\r
746\r
747static PyObject *\r
748fileio_seek(fileio *self, PyObject *args)\r
749{\r
750 PyObject *posobj;\r
751 int whence = 0;\r
752\r
753 if (self->fd < 0)\r
754 return err_closed();\r
755\r
756 if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))\r
757 return NULL;\r
758\r
759 return portable_lseek(self->fd, posobj, whence);\r
760}\r
761\r
762static PyObject *\r
763fileio_tell(fileio *self, PyObject *args)\r
764{\r
765 if (self->fd < 0)\r
766 return err_closed();\r
767\r
768 return portable_lseek(self->fd, NULL, 1);\r
769}\r
770\r
771#ifdef HAVE_FTRUNCATE\r
772static PyObject *\r
773fileio_truncate(fileio *self, PyObject *args)\r
774{\r
775 PyObject *posobj = NULL; /* the new size wanted by the user */\r
776#ifndef MS_WINDOWS\r
777 Py_off_t pos;\r
778#endif\r
779 int ret;\r
780 int fd;\r
781\r
782 fd = self->fd;\r
783 if (fd < 0)\r
784 return err_closed();\r
785 if (!self->writable)\r
786 return err_mode("writing");\r
787\r
788 if (!PyArg_ParseTuple(args, "|O", &posobj))\r
789 return NULL;\r
790\r
791 if (posobj == Py_None || posobj == NULL) {\r
792 /* Get the current position. */\r
793 posobj = portable_lseek(fd, NULL, 1);\r
794 if (posobj == NULL)\r
795 return NULL;\r
796 }\r
797 else {\r
798 Py_INCREF(posobj);\r
799 }\r
800\r
801#ifdef MS_WINDOWS\r
802 /* MS _chsize doesn't work if newsize doesn't fit in 32 bits,\r
803 so don't even try using it. */\r
804 {\r
805 PyObject *oldposobj, *tempposobj;\r
806 HANDLE hFile;\r
807\r
808 /* we save the file pointer position */\r
809 oldposobj = portable_lseek(fd, NULL, 1);\r
810 if (oldposobj == NULL) {\r
811 Py_DECREF(posobj);\r
812 return NULL;\r
813 }\r
814\r
815 /* we then move to the truncation position */\r
816 tempposobj = portable_lseek(fd, posobj, 0);\r
817 if (tempposobj == NULL) {\r
818 Py_DECREF(oldposobj);\r
819 Py_DECREF(posobj);\r
820 return NULL;\r
821 }\r
822 Py_DECREF(tempposobj);\r
823\r
824 /* Truncate. Note that this may grow the file! */\r
825 Py_BEGIN_ALLOW_THREADS\r
826 errno = 0;\r
827 hFile = (HANDLE)_get_osfhandle(fd);\r
828 ret = hFile == (HANDLE)-1; /* testing for INVALID_HANDLE value */\r
829 if (ret == 0) {\r
830 ret = SetEndOfFile(hFile) == 0;\r
831 if (ret)\r
832 errno = EACCES;\r
833 }\r
834 Py_END_ALLOW_THREADS\r
835\r
836 /* we restore the file pointer position in any case */\r
837 tempposobj = portable_lseek(fd, oldposobj, 0);\r
838 Py_DECREF(oldposobj);\r
839 if (tempposobj == NULL) {\r
840 Py_DECREF(posobj);\r
841 return NULL;\r
842 }\r
843 Py_DECREF(tempposobj);\r
844 }\r
845#else\r
846\r
847#if defined(HAVE_LARGEFILE_SUPPORT)\r
848 pos = PyLong_AsLongLong(posobj);\r
849#else\r
850 pos = PyLong_AsLong(posobj);\r
851#endif\r
852 if (PyErr_Occurred()){\r
853 Py_DECREF(posobj);\r
854 return NULL;\r
855 }\r
856\r
857 Py_BEGIN_ALLOW_THREADS\r
858 errno = 0;\r
859 ret = ftruncate(fd, pos);\r
860 Py_END_ALLOW_THREADS\r
861\r
862#endif /* !MS_WINDOWS */\r
863\r
864 if (ret != 0) {\r
865 Py_DECREF(posobj);\r
866 PyErr_SetFromErrno(PyExc_IOError);\r
867 return NULL;\r
868 }\r
869\r
870 return posobj;\r
871}\r
872#endif /* HAVE_FTRUNCATE */\r
873\r
874static char *\r
875mode_string(fileio *self)\r
876{\r
877 if (self->readable) {\r
878 if (self->writable)\r
879 return "rb+";\r
880 else\r
881 return "rb";\r
882 }\r
883 else\r
884 return "wb";\r
885}\r
886\r
887static PyObject *\r
888fileio_repr(fileio *self)\r
889{\r
890 PyObject *nameobj, *res;\r
891\r
892 if (self->fd < 0)\r
893 return PyString_FromFormat("<_io.FileIO [closed]>");\r
894\r
895 nameobj = PyObject_GetAttrString((PyObject *) self, "name");\r
896 if (nameobj == NULL) {\r
897 if (PyErr_ExceptionMatches(PyExc_AttributeError))\r
898 PyErr_Clear();\r
899 else\r
900 return NULL;\r
901 res = PyString_FromFormat("<_io.FileIO fd=%d mode='%s'>",\r
902 self->fd, mode_string(self));\r
903 }\r
904 else {\r
905 PyObject *repr = PyObject_Repr(nameobj);\r
906 Py_DECREF(nameobj);\r
907 if (repr == NULL)\r
908 return NULL;\r
909 res = PyString_FromFormat("<_io.FileIO name=%s mode='%s'>",\r
910 PyString_AS_STRING(repr),\r
911 mode_string(self));\r
912 Py_DECREF(repr);\r
913 }\r
914 return res;\r
915}\r
916\r
917static PyObject *\r
918fileio_isatty(fileio *self)\r
919{\r
920 long res;\r
921\r
922 if (self->fd < 0)\r
923 return err_closed();\r
924 Py_BEGIN_ALLOW_THREADS\r
925 res = isatty(self->fd);\r
926 Py_END_ALLOW_THREADS\r
927 return PyBool_FromLong(res);\r
928}\r
929\r
930\r
931PyDoc_STRVAR(fileio_doc,\r
932"file(name: str[, mode: str]) -> file IO object\n"\r
933"\n"\r
934"Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n"\r
935"writing or appending. The file will be created if it doesn't exist\n"\r
936"when opened for writing or appending; it will be truncated when\n"\r
937"opened for writing. Add a '+' to the mode to allow simultaneous\n"\r
938"reading and writing.");\r
939\r
940PyDoc_STRVAR(read_doc,\r
941"read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"\r
942"\n"\r
943"Only makes one system call, so less data may be returned than requested\n"\r
944"In non-blocking mode, returns None if no data is available.\n"\r
945"On end-of-file, returns ''.");\r
946\r
947PyDoc_STRVAR(readall_doc,\r
948"readall() -> bytes. read all data from the file, returned as bytes.\n"\r
949"\n"\r
950"In non-blocking mode, returns as much as is immediately available,\n"\r
951"or None if no data is available. On end-of-file, returns ''.");\r
952\r
953PyDoc_STRVAR(write_doc,\r
954"write(b: bytes) -> int. Write bytes b to file, return number written.\n"\r
955"\n"\r
956"Only makes one system call, so not all of the data may be written.\n"\r
957"The number of bytes actually written is returned.");\r
958\r
959PyDoc_STRVAR(fileno_doc,\r
960"fileno() -> int. \"file descriptor\".\n"\r
961"\n"\r
962"This is needed for lower-level file interfaces, such the fcntl module.");\r
963\r
964PyDoc_STRVAR(seek_doc,\r
965"seek(offset: int[, whence: int]) -> None. Move to new file position.\n"\r
966"\n"\r
967"Argument offset is a byte count. Optional argument whence defaults to\n"\r
968"0 (offset from start of file, offset should be >= 0); other values are 1\n"\r
969"(move relative to current position, positive or negative), and 2 (move\n"\r
970"relative to end of file, usually negative, although many platforms allow\n"\r
971"seeking beyond the end of a file)."\r
972"\n"\r
973"Note that not all file objects are seekable.");\r
974\r
975#ifdef HAVE_FTRUNCATE\r
976PyDoc_STRVAR(truncate_doc,\r
977"truncate([size: int]) -> None. Truncate the file to at most size bytes.\n"\r
978"\n"\r
979"Size defaults to the current file position, as returned by tell()."\r
980"The current file position is changed to the value of size.");\r
981#endif\r
982\r
983PyDoc_STRVAR(tell_doc,\r
984"tell() -> int. Current file position");\r
985\r
986PyDoc_STRVAR(readinto_doc,\r
987"readinto() -> Same as RawIOBase.readinto().");\r
988\r
989PyDoc_STRVAR(close_doc,\r
990"close() -> None. Close the file.\n"\r
991"\n"\r
992"A closed file cannot be used for further I/O operations. close() may be\n"\r
993"called more than once without error. Changes the fileno to -1.");\r
994\r
995PyDoc_STRVAR(isatty_doc,\r
996"isatty() -> bool. True if the file is connected to a tty device.");\r
997\r
998PyDoc_STRVAR(seekable_doc,\r
999"seekable() -> bool. True if file supports random-access.");\r
1000\r
1001PyDoc_STRVAR(readable_doc,\r
1002"readable() -> bool. True if file was opened in a read mode.");\r
1003\r
1004PyDoc_STRVAR(writable_doc,\r
1005"writable() -> bool. True if file was opened in a write mode.");\r
1006\r
1007static PyMethodDef fileio_methods[] = {\r
1008 {"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc},\r
1009 {"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc},\r
1010 {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},\r
1011 {"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc},\r
1012 {"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc},\r
1013 {"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc},\r
1014#ifdef HAVE_FTRUNCATE\r
1015 {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},\r
1016#endif\r
1017 {"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc},\r
1018 {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc},\r
1019 {"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc},\r
1020 {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc},\r
1021 {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc},\r
1022 {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc},\r
1023 {NULL, NULL} /* sentinel */\r
1024};\r
1025\r
1026/* 'closed' and 'mode' are attributes for backwards compatibility reasons. */\r
1027\r
1028static PyObject *\r
1029get_closed(fileio *self, void *closure)\r
1030{\r
1031 return PyBool_FromLong((long)(self->fd < 0));\r
1032}\r
1033\r
1034static PyObject *\r
1035get_closefd(fileio *self, void *closure)\r
1036{\r
1037 return PyBool_FromLong((long)(self->closefd));\r
1038}\r
1039\r
1040static PyObject *\r
1041get_mode(fileio *self, void *closure)\r
1042{\r
1043 return PyUnicode_FromString(mode_string(self));\r
1044}\r
1045\r
1046static PyGetSetDef fileio_getsetlist[] = {\r
1047 {"closed", (getter)get_closed, NULL, "True if the file is closed"},\r
1048 {"closefd", (getter)get_closefd, NULL,\r
1049 "True if the file descriptor will be closed"},\r
1050 {"mode", (getter)get_mode, NULL, "String giving the file mode"},\r
1051 {NULL},\r
1052};\r
1053\r
1054PyTypeObject PyFileIO_Type = {\r
1055 PyVarObject_HEAD_INIT(NULL, 0)\r
1056 "_io.FileIO",\r
1057 sizeof(fileio),\r
1058 0,\r
1059 (destructor)fileio_dealloc, /* tp_dealloc */\r
1060 0, /* tp_print */\r
1061 0, /* tp_getattr */\r
1062 0, /* tp_setattr */\r
1063 0, /* tp_reserved */\r
1064 (reprfunc)fileio_repr, /* tp_repr */\r
1065 0, /* tp_as_number */\r
1066 0, /* tp_as_sequence */\r
1067 0, /* tp_as_mapping */\r
1068 0, /* tp_hash */\r
1069 0, /* tp_call */\r
1070 0, /* tp_str */\r
1071 PyObject_GenericGetAttr, /* tp_getattro */\r
1072 0, /* tp_setattro */\r
1073 0, /* tp_as_buffer */\r
1074 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE\r
1075 | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r
1076 fileio_doc, /* tp_doc */\r
1077 (traverseproc)fileio_traverse, /* tp_traverse */\r
1078 (inquiry)fileio_clear, /* tp_clear */\r
1079 0, /* tp_richcompare */\r
1080 offsetof(fileio, weakreflist), /* tp_weaklistoffset */\r
1081 0, /* tp_iter */\r
1082 0, /* tp_iternext */\r
1083 fileio_methods, /* tp_methods */\r
1084 0, /* tp_members */\r
1085 fileio_getsetlist, /* tp_getset */\r
1086 0, /* tp_base */\r
1087 0, /* tp_dict */\r
1088 0, /* tp_descr_get */\r
1089 0, /* tp_descr_set */\r
1090 offsetof(fileio, dict), /* tp_dictoffset */\r
1091 fileio_init, /* tp_init */\r
1092 PyType_GenericAlloc, /* tp_alloc */\r
1093 fileio_new, /* tp_new */\r
1094 PyObject_GC_Del, /* tp_free */\r
1095};\r