|
1 /* 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 |
|
30 typedef 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 |
|
40 PyTypeObject 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. */ |
|
45 static int |
|
46 internal_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 |
|
60 static PyObject * |
|
61 fileio_close(PyFileIOObject *self) |
|
62 { |
|
63 if (!self->closefd) { |
|
64 if (PyErr_WarnEx(PyExc_RuntimeWarning, |
|
65 "Trying to close unclosable fd!", 3) < 0) { |
|
66 return NULL; |
|
67 } |
|
68 Py_RETURN_NONE; |
|
69 } |
|
70 errno = internal_close(self); |
|
71 if (errno < 0) { |
|
72 PyErr_SetFromErrno(PyExc_IOError); |
|
73 return NULL; |
|
74 } |
|
75 |
|
76 Py_RETURN_NONE; |
|
77 } |
|
78 |
|
79 static PyObject * |
|
80 fileio_new(PyTypeObject *type, PyObject *args, PyObject *kews) |
|
81 { |
|
82 PyFileIOObject *self; |
|
83 |
|
84 assert(type != NULL && type->tp_alloc != NULL); |
|
85 |
|
86 self = (PyFileIOObject *) type->tp_alloc(type, 0); |
|
87 if (self != NULL) { |
|
88 self->fd = -1; |
|
89 self->readable = 0; |
|
90 self->writable = 0; |
|
91 self->seekable = -1; |
|
92 self->closefd = 1; |
|
93 self->weakreflist = NULL; |
|
94 } |
|
95 |
|
96 return (PyObject *) self; |
|
97 } |
|
98 |
|
99 /* On Unix, open will succeed for directories. |
|
100 In Python, there should be no file objects referring to |
|
101 directories, so we need a check. */ |
|
102 |
|
103 static int |
|
104 dircheck(PyFileIOObject* self) |
|
105 { |
|
106 #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) |
|
107 struct stat buf; |
|
108 if (self->fd < 0) |
|
109 return 0; |
|
110 if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) { |
|
111 char *msg = strerror(EISDIR); |
|
112 PyObject *exc; |
|
113 internal_close(self); |
|
114 |
|
115 exc = PyObject_CallFunction(PyExc_IOError, "(is)", |
|
116 EISDIR, msg); |
|
117 PyErr_SetObject(PyExc_IOError, exc); |
|
118 Py_XDECREF(exc); |
|
119 return -1; |
|
120 } |
|
121 #endif |
|
122 return 0; |
|
123 } |
|
124 |
|
125 |
|
126 static int |
|
127 fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) |
|
128 { |
|
129 PyFileIOObject *self = (PyFileIOObject *) oself; |
|
130 static char *kwlist[] = {"file", "mode", "closefd", NULL}; |
|
131 char *name = NULL; |
|
132 char *mode = "r"; |
|
133 char *s; |
|
134 #ifdef MS_WINDOWS |
|
135 Py_UNICODE *widename = NULL; |
|
136 #endif |
|
137 int ret = 0; |
|
138 int rwa = 0, plus = 0, append = 0; |
|
139 int flags = 0; |
|
140 int fd = -1; |
|
141 int closefd = 1; |
|
142 |
|
143 assert(PyFileIO_Check(oself)); |
|
144 if (self->fd >= 0) { |
|
145 /* Have to close the existing file first. */ |
|
146 if (internal_close(self) < 0) |
|
147 return -1; |
|
148 } |
|
149 |
|
150 if (PyArg_ParseTupleAndKeywords(args, kwds, "i|si:fileio", |
|
151 kwlist, &fd, &mode, &closefd)) { |
|
152 if (fd < 0) { |
|
153 PyErr_SetString(PyExc_ValueError, |
|
154 "Negative filedescriptor"); |
|
155 return -1; |
|
156 } |
|
157 } |
|
158 else { |
|
159 PyErr_Clear(); |
|
160 |
|
161 #ifdef Py_WIN_WIDE_FILENAMES |
|
162 if (GetVersion() < 0x80000000) { |
|
163 /* On NT, so wide API available */ |
|
164 PyObject *po; |
|
165 if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:fileio", |
|
166 kwlist, &po, &mode, &closefd) |
|
167 ) { |
|
168 widename = PyUnicode_AS_UNICODE(po); |
|
169 } else { |
|
170 /* Drop the argument parsing error as narrow |
|
171 strings are also valid. */ |
|
172 PyErr_Clear(); |
|
173 } |
|
174 } |
|
175 if (widename == NULL) |
|
176 #endif |
|
177 { |
|
178 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:fileio", |
|
179 kwlist, |
|
180 Py_FileSystemDefaultEncoding, |
|
181 &name, &mode, &closefd)) |
|
182 return -1; |
|
183 } |
|
184 } |
|
185 |
|
186 s = mode; |
|
187 while (*s) { |
|
188 switch (*s++) { |
|
189 case 'r': |
|
190 if (rwa) { |
|
191 bad_mode: |
|
192 PyErr_SetString(PyExc_ValueError, |
|
193 "Must have exactly one of read/write/append mode"); |
|
194 goto error; |
|
195 } |
|
196 rwa = 1; |
|
197 self->readable = 1; |
|
198 break; |
|
199 case 'w': |
|
200 if (rwa) |
|
201 goto bad_mode; |
|
202 rwa = 1; |
|
203 self->writable = 1; |
|
204 flags |= O_CREAT | O_TRUNC; |
|
205 break; |
|
206 case 'a': |
|
207 if (rwa) |
|
208 goto bad_mode; |
|
209 rwa = 1; |
|
210 self->writable = 1; |
|
211 flags |= O_CREAT; |
|
212 append = 1; |
|
213 break; |
|
214 case '+': |
|
215 if (plus) |
|
216 goto bad_mode; |
|
217 self->readable = self->writable = 1; |
|
218 plus = 1; |
|
219 break; |
|
220 default: |
|
221 PyErr_Format(PyExc_ValueError, |
|
222 "invalid mode: %.200s", mode); |
|
223 goto error; |
|
224 } |
|
225 } |
|
226 |
|
227 if (!rwa) |
|
228 goto bad_mode; |
|
229 |
|
230 if (self->readable && self->writable) |
|
231 flags |= O_RDWR; |
|
232 else if (self->readable) |
|
233 flags |= O_RDONLY; |
|
234 else |
|
235 flags |= O_WRONLY; |
|
236 |
|
237 #ifdef O_BINARY |
|
238 flags |= O_BINARY; |
|
239 #endif |
|
240 |
|
241 #ifdef O_APPEND |
|
242 if (append) |
|
243 flags |= O_APPEND; |
|
244 #endif |
|
245 |
|
246 if (fd >= 0) { |
|
247 self->fd = fd; |
|
248 self->closefd = closefd; |
|
249 } |
|
250 else { |
|
251 self->closefd = 1; |
|
252 if (!closefd) { |
|
253 PyErr_SetString(PyExc_ValueError, |
|
254 "Cannot use closefd=False with file name"); |
|
255 goto error; |
|
256 } |
|
257 |
|
258 Py_BEGIN_ALLOW_THREADS |
|
259 errno = 0; |
|
260 #ifdef MS_WINDOWS |
|
261 if (widename != NULL) |
|
262 self->fd = _wopen(widename, flags, 0666); |
|
263 else |
|
264 #endif |
|
265 self->fd = open(name, flags, 0666); |
|
266 Py_END_ALLOW_THREADS |
|
267 if (self->fd < 0) { |
|
268 #ifdef MS_WINDOWS |
|
269 PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename); |
|
270 #else |
|
271 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name); |
|
272 #endif |
|
273 goto error; |
|
274 } |
|
275 if(dircheck(self) < 0) |
|
276 goto error; |
|
277 } |
|
278 |
|
279 goto done; |
|
280 |
|
281 error: |
|
282 ret = -1; |
|
283 |
|
284 done: |
|
285 PyMem_Free(name); |
|
286 return ret; |
|
287 } |
|
288 |
|
289 static void |
|
290 fileio_dealloc(PyFileIOObject *self) |
|
291 { |
|
292 if (self->weakreflist != NULL) |
|
293 PyObject_ClearWeakRefs((PyObject *) self); |
|
294 |
|
295 if (self->fd >= 0 && self->closefd) { |
|
296 errno = internal_close(self); |
|
297 if (errno < 0) { |
|
298 PySys_WriteStderr("close failed: [Errno %d] %s\n", |
|
299 errno, strerror(errno)); |
|
300 } |
|
301 } |
|
302 |
|
303 Py_TYPE(self)->tp_free((PyObject *)self); |
|
304 } |
|
305 |
|
306 static PyObject * |
|
307 err_closed(void) |
|
308 { |
|
309 PyErr_SetString(PyExc_ValueError, "I/O operation on closed file"); |
|
310 return NULL; |
|
311 } |
|
312 |
|
313 static PyObject * |
|
314 err_mode(char *action) |
|
315 { |
|
316 PyErr_Format(PyExc_ValueError, "File not open for %s", action); |
|
317 return NULL; |
|
318 } |
|
319 |
|
320 static PyObject * |
|
321 fileio_fileno(PyFileIOObject *self) |
|
322 { |
|
323 if (self->fd < 0) |
|
324 return err_closed(); |
|
325 return PyInt_FromLong((long) self->fd); |
|
326 } |
|
327 |
|
328 static PyObject * |
|
329 fileio_readable(PyFileIOObject *self) |
|
330 { |
|
331 if (self->fd < 0) |
|
332 return err_closed(); |
|
333 return PyBool_FromLong((long) self->readable); |
|
334 } |
|
335 |
|
336 static PyObject * |
|
337 fileio_writable(PyFileIOObject *self) |
|
338 { |
|
339 if (self->fd < 0) |
|
340 return err_closed(); |
|
341 return PyBool_FromLong((long) self->writable); |
|
342 } |
|
343 |
|
344 static PyObject * |
|
345 fileio_seekable(PyFileIOObject *self) |
|
346 { |
|
347 if (self->fd < 0) |
|
348 return err_closed(); |
|
349 if (self->seekable < 0) { |
|
350 int ret; |
|
351 Py_BEGIN_ALLOW_THREADS |
|
352 ret = lseek(self->fd, 0, SEEK_CUR); |
|
353 Py_END_ALLOW_THREADS |
|
354 if (ret < 0) |
|
355 self->seekable = 0; |
|
356 else |
|
357 self->seekable = 1; |
|
358 } |
|
359 return PyBool_FromLong((long) self->seekable); |
|
360 } |
|
361 |
|
362 static PyObject * |
|
363 fileio_readinto(PyFileIOObject *self, PyObject *args) |
|
364 { |
|
365 Py_buffer pbuf; |
|
366 Py_ssize_t n; |
|
367 |
|
368 if (self->fd < 0) |
|
369 return err_closed(); |
|
370 if (!self->readable) |
|
371 return err_mode("reading"); |
|
372 |
|
373 if (!PyArg_ParseTuple(args, "w*", &pbuf)) |
|
374 return NULL; |
|
375 |
|
376 Py_BEGIN_ALLOW_THREADS |
|
377 errno = 0; |
|
378 n = read(self->fd, pbuf.buf, pbuf.len); |
|
379 Py_END_ALLOW_THREADS |
|
380 PyBuffer_Release(&pbuf); |
|
381 if (n < 0) { |
|
382 if (errno == EAGAIN) |
|
383 Py_RETURN_NONE; |
|
384 PyErr_SetFromErrno(PyExc_IOError); |
|
385 return NULL; |
|
386 } |
|
387 |
|
388 return PyLong_FromSsize_t(n); |
|
389 } |
|
390 |
|
391 #define DEFAULT_BUFFER_SIZE (8*1024) |
|
392 |
|
393 static PyObject * |
|
394 fileio_readall(PyFileIOObject *self) |
|
395 { |
|
396 PyObject *result; |
|
397 Py_ssize_t total = 0; |
|
398 int n; |
|
399 |
|
400 result = PyString_FromStringAndSize(NULL, DEFAULT_BUFFER_SIZE); |
|
401 if (result == NULL) |
|
402 return NULL; |
|
403 |
|
404 while (1) { |
|
405 Py_ssize_t newsize = total + DEFAULT_BUFFER_SIZE; |
|
406 if (PyString_GET_SIZE(result) < newsize) { |
|
407 if (_PyString_Resize(&result, newsize) < 0) { |
|
408 if (total == 0) { |
|
409 Py_DECREF(result); |
|
410 return NULL; |
|
411 } |
|
412 PyErr_Clear(); |
|
413 break; |
|
414 } |
|
415 } |
|
416 Py_BEGIN_ALLOW_THREADS |
|
417 errno = 0; |
|
418 n = read(self->fd, |
|
419 PyString_AS_STRING(result) + total, |
|
420 newsize - total); |
|
421 Py_END_ALLOW_THREADS |
|
422 if (n == 0) |
|
423 break; |
|
424 if (n < 0) { |
|
425 if (total > 0) |
|
426 break; |
|
427 if (errno == EAGAIN) { |
|
428 Py_DECREF(result); |
|
429 Py_RETURN_NONE; |
|
430 } |
|
431 Py_DECREF(result); |
|
432 PyErr_SetFromErrno(PyExc_IOError); |
|
433 return NULL; |
|
434 } |
|
435 total += n; |
|
436 } |
|
437 |
|
438 if (PyString_GET_SIZE(result) > total) { |
|
439 if (_PyString_Resize(&result, total) < 0) { |
|
440 /* This should never happen, but just in case */ |
|
441 Py_DECREF(result); |
|
442 return NULL; |
|
443 } |
|
444 } |
|
445 return result; |
|
446 } |
|
447 |
|
448 static PyObject * |
|
449 fileio_read(PyFileIOObject *self, PyObject *args) |
|
450 { |
|
451 char *ptr; |
|
452 Py_ssize_t n; |
|
453 Py_ssize_t size = -1; |
|
454 PyObject *bytes; |
|
455 |
|
456 if (self->fd < 0) |
|
457 return err_closed(); |
|
458 if (!self->readable) |
|
459 return err_mode("reading"); |
|
460 |
|
461 if (!PyArg_ParseTuple(args, "|n", &size)) |
|
462 return NULL; |
|
463 |
|
464 if (size < 0) { |
|
465 return fileio_readall(self); |
|
466 } |
|
467 |
|
468 bytes = PyString_FromStringAndSize(NULL, size); |
|
469 if (bytes == NULL) |
|
470 return NULL; |
|
471 ptr = PyString_AS_STRING(bytes); |
|
472 |
|
473 Py_BEGIN_ALLOW_THREADS |
|
474 errno = 0; |
|
475 n = read(self->fd, ptr, size); |
|
476 Py_END_ALLOW_THREADS |
|
477 |
|
478 if (n < 0) { |
|
479 if (errno == EAGAIN) |
|
480 Py_RETURN_NONE; |
|
481 PyErr_SetFromErrno(PyExc_IOError); |
|
482 return NULL; |
|
483 } |
|
484 |
|
485 if (n != size) { |
|
486 if (_PyString_Resize(&bytes, n) < 0) { |
|
487 Py_DECREF(bytes); |
|
488 return NULL; |
|
489 } |
|
490 } |
|
491 |
|
492 return (PyObject *) bytes; |
|
493 } |
|
494 |
|
495 static PyObject * |
|
496 fileio_write(PyFileIOObject *self, PyObject *args) |
|
497 { |
|
498 Py_buffer pbuf; |
|
499 Py_ssize_t n; |
|
500 |
|
501 if (self->fd < 0) |
|
502 return err_closed(); |
|
503 if (!self->writable) |
|
504 return err_mode("writing"); |
|
505 |
|
506 if (!PyArg_ParseTuple(args, "s*", &pbuf)) |
|
507 return NULL; |
|
508 |
|
509 Py_BEGIN_ALLOW_THREADS |
|
510 errno = 0; |
|
511 n = write(self->fd, pbuf.buf, pbuf.len); |
|
512 Py_END_ALLOW_THREADS |
|
513 |
|
514 PyBuffer_Release(&pbuf); |
|
515 |
|
516 if (n < 0) { |
|
517 if (errno == EAGAIN) |
|
518 Py_RETURN_NONE; |
|
519 PyErr_SetFromErrno(PyExc_IOError); |
|
520 return NULL; |
|
521 } |
|
522 |
|
523 return PyLong_FromSsize_t(n); |
|
524 } |
|
525 |
|
526 /* XXX Windows support below is likely incomplete */ |
|
527 |
|
528 #if defined(MS_WIN64) || defined(MS_WINDOWS) |
|
529 typedef PY_LONG_LONG Py_off_t; |
|
530 #else |
|
531 typedef off_t Py_off_t; |
|
532 #endif |
|
533 |
|
534 /* Cribbed from posix_lseek() */ |
|
535 static PyObject * |
|
536 portable_lseek(int fd, PyObject *posobj, int whence) |
|
537 { |
|
538 Py_off_t pos, res; |
|
539 |
|
540 #ifdef SEEK_SET |
|
541 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */ |
|
542 switch (whence) { |
|
543 #if SEEK_SET != 0 |
|
544 case 0: whence = SEEK_SET; break; |
|
545 #endif |
|
546 #if SEEK_CUR != 1 |
|
547 case 1: whence = SEEK_CUR; break; |
|
548 #endif |
|
549 #if SEEL_END != 2 |
|
550 case 2: whence = SEEK_END; break; |
|
551 #endif |
|
552 } |
|
553 #endif /* SEEK_SET */ |
|
554 |
|
555 if (posobj == NULL) |
|
556 pos = 0; |
|
557 else { |
|
558 if(PyFloat_Check(posobj)) { |
|
559 PyErr_SetString(PyExc_TypeError, "an integer is required"); |
|
560 return NULL; |
|
561 } |
|
562 #if defined(HAVE_LARGEFILE_SUPPORT) |
|
563 pos = PyLong_AsLongLong(posobj); |
|
564 #else |
|
565 pos = PyLong_AsLong(posobj); |
|
566 #endif |
|
567 if (PyErr_Occurred()) |
|
568 return NULL; |
|
569 } |
|
570 |
|
571 Py_BEGIN_ALLOW_THREADS |
|
572 #if defined(MS_WIN64) || defined(MS_WINDOWS) |
|
573 res = _lseeki64(fd, pos, whence); |
|
574 #else |
|
575 res = lseek(fd, pos, whence); |
|
576 #endif |
|
577 Py_END_ALLOW_THREADS |
|
578 if (res < 0) |
|
579 return PyErr_SetFromErrno(PyExc_IOError); |
|
580 |
|
581 #if defined(HAVE_LARGEFILE_SUPPORT) |
|
582 return PyLong_FromLongLong(res); |
|
583 #else |
|
584 return PyLong_FromLong(res); |
|
585 #endif |
|
586 } |
|
587 |
|
588 static PyObject * |
|
589 fileio_seek(PyFileIOObject *self, PyObject *args) |
|
590 { |
|
591 PyObject *posobj; |
|
592 int whence = 0; |
|
593 |
|
594 if (self->fd < 0) |
|
595 return err_closed(); |
|
596 |
|
597 if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence)) |
|
598 return NULL; |
|
599 |
|
600 return portable_lseek(self->fd, posobj, whence); |
|
601 } |
|
602 |
|
603 static PyObject * |
|
604 fileio_tell(PyFileIOObject *self, PyObject *args) |
|
605 { |
|
606 if (self->fd < 0) |
|
607 return err_closed(); |
|
608 |
|
609 return portable_lseek(self->fd, NULL, 1); |
|
610 } |
|
611 |
|
612 #ifdef HAVE_FTRUNCATE |
|
613 static PyObject * |
|
614 fileio_truncate(PyFileIOObject *self, PyObject *args) |
|
615 { |
|
616 PyObject *posobj = NULL; |
|
617 Py_off_t pos; |
|
618 int ret; |
|
619 int fd; |
|
620 |
|
621 fd = self->fd; |
|
622 if (fd < 0) |
|
623 return err_closed(); |
|
624 if (!self->writable) |
|
625 return err_mode("writing"); |
|
626 |
|
627 if (!PyArg_ParseTuple(args, "|O", &posobj)) |
|
628 return NULL; |
|
629 |
|
630 if (posobj == Py_None || posobj == NULL) { |
|
631 /* Get the current position. */ |
|
632 posobj = portable_lseek(fd, NULL, 1); |
|
633 if (posobj == NULL) |
|
634 return NULL; |
|
635 } |
|
636 else { |
|
637 /* Move to the position to be truncated. */ |
|
638 posobj = portable_lseek(fd, posobj, 0); |
|
639 } |
|
640 |
|
641 #if defined(HAVE_LARGEFILE_SUPPORT) |
|
642 pos = PyLong_AsLongLong(posobj); |
|
643 #else |
|
644 pos = PyLong_AsLong(posobj); |
|
645 #endif |
|
646 if (PyErr_Occurred()) |
|
647 return NULL; |
|
648 |
|
649 #ifdef MS_WINDOWS |
|
650 /* MS _chsize doesn't work if newsize doesn't fit in 32 bits, |
|
651 so don't even try using it. */ |
|
652 { |
|
653 HANDLE hFile; |
|
654 |
|
655 /* Truncate. Note that this may grow the file! */ |
|
656 Py_BEGIN_ALLOW_THREADS |
|
657 errno = 0; |
|
658 hFile = (HANDLE)_get_osfhandle(fd); |
|
659 ret = hFile == (HANDLE)-1; |
|
660 if (ret == 0) { |
|
661 ret = SetEndOfFile(hFile) == 0; |
|
662 if (ret) |
|
663 errno = EACCES; |
|
664 } |
|
665 Py_END_ALLOW_THREADS |
|
666 } |
|
667 #else |
|
668 Py_BEGIN_ALLOW_THREADS |
|
669 errno = 0; |
|
670 ret = ftruncate(fd, pos); |
|
671 Py_END_ALLOW_THREADS |
|
672 #endif /* !MS_WINDOWS */ |
|
673 |
|
674 if (ret != 0) { |
|
675 PyErr_SetFromErrno(PyExc_IOError); |
|
676 return NULL; |
|
677 } |
|
678 |
|
679 return posobj; |
|
680 } |
|
681 #endif |
|
682 |
|
683 static char * |
|
684 mode_string(PyFileIOObject *self) |
|
685 { |
|
686 if (self->readable) { |
|
687 if (self->writable) |
|
688 return "r+"; |
|
689 else |
|
690 return "r"; |
|
691 } |
|
692 else |
|
693 return "w"; |
|
694 } |
|
695 |
|
696 static PyObject * |
|
697 fileio_repr(PyFileIOObject *self) |
|
698 { |
|
699 if (self->fd < 0) |
|
700 return PyString_FromFormat("_fileio._FileIO(-1)"); |
|
701 |
|
702 return PyString_FromFormat("_fileio._FileIO(%d, '%s')", |
|
703 self->fd, mode_string(self)); |
|
704 } |
|
705 |
|
706 static PyObject * |
|
707 fileio_isatty(PyFileIOObject *self) |
|
708 { |
|
709 long res; |
|
710 |
|
711 if (self->fd < 0) |
|
712 return err_closed(); |
|
713 Py_BEGIN_ALLOW_THREADS |
|
714 res = isatty(self->fd); |
|
715 Py_END_ALLOW_THREADS |
|
716 return PyBool_FromLong(res); |
|
717 } |
|
718 |
|
719 |
|
720 PyDoc_STRVAR(fileio_doc, |
|
721 "file(name: str[, mode: str]) -> file IO object\n" |
|
722 "\n" |
|
723 "Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n" |
|
724 "writing or appending. The file will be created if it doesn't exist\n" |
|
725 "when opened for writing or appending; it will be truncated when\n" |
|
726 "opened for writing. Add a '+' to the mode to allow simultaneous\n" |
|
727 "reading and writing."); |
|
728 |
|
729 PyDoc_STRVAR(read_doc, |
|
730 "read(size: int) -> bytes. read at most size bytes, returned as bytes.\n" |
|
731 "\n" |
|
732 "Only makes one system call, so less data may be returned than requested\n" |
|
733 "In non-blocking mode, returns None if no data is available.\n" |
|
734 "On end-of-file, returns ''."); |
|
735 |
|
736 PyDoc_STRVAR(readall_doc, |
|
737 "readall() -> bytes. read all data from the file, returned as bytes.\n" |
|
738 "\n" |
|
739 "In non-blocking mode, returns as much as is immediately available,\n" |
|
740 "or None if no data is available. On end-of-file, returns ''."); |
|
741 |
|
742 PyDoc_STRVAR(write_doc, |
|
743 "write(b: bytes) -> int. Write bytes b to file, return number written.\n" |
|
744 "\n" |
|
745 "Only makes one system call, so not all of the data may be written.\n" |
|
746 "The number of bytes actually written is returned."); |
|
747 |
|
748 PyDoc_STRVAR(fileno_doc, |
|
749 "fileno() -> int. \"file descriptor\".\n" |
|
750 "\n" |
|
751 "This is needed for lower-level file interfaces, such the fcntl module."); |
|
752 |
|
753 PyDoc_STRVAR(seek_doc, |
|
754 "seek(offset: int[, whence: int]) -> None. Move to new file position.\n" |
|
755 "\n" |
|
756 "Argument offset is a byte count. Optional argument whence defaults to\n" |
|
757 "0 (offset from start of file, offset should be >= 0); other values are 1\n" |
|
758 "(move relative to current position, positive or negative), and 2 (move\n" |
|
759 "relative to end of file, usually negative, although many platforms allow\n" |
|
760 "seeking beyond the end of a file)." |
|
761 "\n" |
|
762 "Note that not all file objects are seekable."); |
|
763 |
|
764 #ifdef HAVE_FTRUNCATE |
|
765 PyDoc_STRVAR(truncate_doc, |
|
766 "truncate([size: int]) -> None. Truncate the file to at most size bytes.\n" |
|
767 "\n" |
|
768 "Size defaults to the current file position, as returned by tell()." |
|
769 "The current file position is changed to the value of size."); |
|
770 #endif |
|
771 |
|
772 PyDoc_STRVAR(tell_doc, |
|
773 "tell() -> int. Current file position"); |
|
774 |
|
775 PyDoc_STRVAR(readinto_doc, |
|
776 "readinto() -> Undocumented. Don't use this; it may go away."); |
|
777 |
|
778 PyDoc_STRVAR(close_doc, |
|
779 "close() -> None. Close the file.\n" |
|
780 "\n" |
|
781 "A closed file cannot be used for further I/O operations. close() may be\n" |
|
782 "called more than once without error. Changes the fileno to -1."); |
|
783 |
|
784 PyDoc_STRVAR(isatty_doc, |
|
785 "isatty() -> bool. True if the file is connected to a tty device."); |
|
786 |
|
787 PyDoc_STRVAR(seekable_doc, |
|
788 "seekable() -> bool. True if file supports random-access."); |
|
789 |
|
790 PyDoc_STRVAR(readable_doc, |
|
791 "readable() -> bool. True if file was opened in a read mode."); |
|
792 |
|
793 PyDoc_STRVAR(writable_doc, |
|
794 "writable() -> bool. True if file was opened in a write mode."); |
|
795 |
|
796 static PyMethodDef fileio_methods[] = { |
|
797 {"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc}, |
|
798 {"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc}, |
|
799 {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc}, |
|
800 {"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc}, |
|
801 {"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc}, |
|
802 {"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc}, |
|
803 #ifdef HAVE_FTRUNCATE |
|
804 {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc}, |
|
805 #endif |
|
806 {"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc}, |
|
807 {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc}, |
|
808 {"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc}, |
|
809 {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc}, |
|
810 {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc}, |
|
811 {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc}, |
|
812 {NULL, NULL} /* sentinel */ |
|
813 }; |
|
814 |
|
815 /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */ |
|
816 |
|
817 static PyObject * |
|
818 get_closed(PyFileIOObject *self, void *closure) |
|
819 { |
|
820 return PyBool_FromLong((long)(self->fd < 0)); |
|
821 } |
|
822 |
|
823 static PyObject * |
|
824 get_mode(PyFileIOObject *self, void *closure) |
|
825 { |
|
826 return PyString_FromString(mode_string(self)); |
|
827 } |
|
828 |
|
829 static PyGetSetDef fileio_getsetlist[] = { |
|
830 {"closed", (getter)get_closed, NULL, "True if the file is closed"}, |
|
831 {"mode", (getter)get_mode, NULL, "String giving the file mode"}, |
|
832 {0}, |
|
833 }; |
|
834 |
|
835 PyTypeObject PyFileIO_Type = { |
|
836 PyVarObject_HEAD_INIT(NULL, 0) |
|
837 "_FileIO", |
|
838 sizeof(PyFileIOObject), |
|
839 0, |
|
840 (destructor)fileio_dealloc, /* tp_dealloc */ |
|
841 0, /* tp_print */ |
|
842 0, /* tp_getattr */ |
|
843 0, /* tp_setattr */ |
|
844 0, /* tp_compare */ |
|
845 (reprfunc)fileio_repr, /* tp_repr */ |
|
846 0, /* tp_as_number */ |
|
847 0, /* tp_as_sequence */ |
|
848 0, /* tp_as_mapping */ |
|
849 0, /* tp_hash */ |
|
850 0, /* tp_call */ |
|
851 0, /* tp_str */ |
|
852 PyObject_GenericGetAttr, /* tp_getattro */ |
|
853 0, /* tp_setattro */ |
|
854 0, /* tp_as_buffer */ |
|
855 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
|
856 fileio_doc, /* tp_doc */ |
|
857 0, /* tp_traverse */ |
|
858 0, /* tp_clear */ |
|
859 0, /* tp_richcompare */ |
|
860 offsetof(PyFileIOObject, weakreflist), /* tp_weaklistoffset */ |
|
861 0, /* tp_iter */ |
|
862 0, /* tp_iternext */ |
|
863 fileio_methods, /* tp_methods */ |
|
864 0, /* tp_members */ |
|
865 fileio_getsetlist, /* tp_getset */ |
|
866 0, /* tp_base */ |
|
867 0, /* tp_dict */ |
|
868 0, /* tp_descr_get */ |
|
869 0, /* tp_descr_set */ |
|
870 0, /* tp_dictoffset */ |
|
871 fileio_init, /* tp_init */ |
|
872 PyType_GenericAlloc, /* tp_alloc */ |
|
873 fileio_new, /* tp_new */ |
|
874 PyObject_Del, /* tp_free */ |
|
875 }; |
|
876 |
|
877 static PyMethodDef module_methods[] = { |
|
878 {NULL, NULL} |
|
879 }; |
|
880 |
|
881 PyMODINIT_FUNC |
|
882 init_fileio(void) |
|
883 { |
|
884 PyObject *m; /* a module object */ |
|
885 |
|
886 m = Py_InitModule3("_fileio", module_methods, |
|
887 "Fast implementation of io.FileIO."); |
|
888 if (m == NULL) |
|
889 return; |
|
890 if (PyType_Ready(&PyFileIO_Type) < 0) |
|
891 return; |
|
892 Py_INCREF(&PyFileIO_Type); |
|
893 PyModule_AddObject(m, "_FileIO", (PyObject *) &PyFileIO_Type); |
|
894 } |