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