• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /* fcntl module */
3 
4 #define PY_SSIZE_T_CLEAN
5 
6 #include "Python.h"
7 
8 #ifdef HAVE_SYS_FILE_H
9 #include <sys/file.h>
10 #endif
11 
12 #include <sys/ioctl.h>
13 #include <fcntl.h>
14 #ifdef HAVE_STROPTS_H
15 #include <stropts.h>
16 #endif
17 
18 static int
conv_descriptor(PyObject * object,int * target)19 conv_descriptor(PyObject *object, int *target)
20 {
21     int fd = PyObject_AsFileDescriptor(object);
22 
23     if (fd < 0)
24         return 0;
25     *target = fd;
26     return 1;
27 }
28 
29 
30 /* fcntl(fd, op, [arg]) */
31 
32 static PyObject *
fcntl_fcntl(PyObject * self,PyObject * args)33 fcntl_fcntl(PyObject *self, PyObject *args)
34 {
35     int fd;
36     int code;
37     int arg;
38     int ret;
39     char *str;
40     Py_ssize_t len;
41     char buf[1024];
42 
43     if (PyArg_ParseTuple(args, "O&is#:fcntl",
44                          conv_descriptor, &fd, &code, &str, &len)) {
45         if (len > sizeof buf) {
46             PyErr_SetString(PyExc_ValueError,
47                             "fcntl string arg too long");
48             return NULL;
49         }
50         memcpy(buf, str, len);
51         Py_BEGIN_ALLOW_THREADS
52         ret = fcntl(fd, code, buf);
53         Py_END_ALLOW_THREADS
54         if (ret < 0) {
55             PyErr_SetFromErrno(PyExc_IOError);
56             return NULL;
57         }
58         return PyString_FromStringAndSize(buf, len);
59     }
60 
61     PyErr_Clear();
62     arg = 0;
63     if (!PyArg_ParseTuple(args,
64          "O&i|I;fcntl requires a file or file descriptor,"
65          " an integer and optionally a third integer or a string",
66                           conv_descriptor, &fd, &code, &arg)) {
67       return NULL;
68     }
69     Py_BEGIN_ALLOW_THREADS
70     ret = fcntl(fd, code, arg);
71     Py_END_ALLOW_THREADS
72     if (ret < 0) {
73         PyErr_SetFromErrno(PyExc_IOError);
74         return NULL;
75     }
76     return PyInt_FromLong((long)ret);
77 }
78 
79 PyDoc_STRVAR(fcntl_doc,
80 "fcntl(fd, op, [arg])\n\
81 \n\
82 Perform the operation op on file descriptor fd.  The values used\n\
83 for op are operating system dependent, and are available\n\
84 as constants in the fcntl module, using the same names as used in\n\
85 the relevant C header files.  The argument arg is optional, and\n\
86 defaults to 0; it may be an int or a string.  If arg is given as a string,\n\
87 the return value of fcntl is a string of that length, containing the\n\
88 resulting value put in the arg buffer by the operating system.  The length\n\
89 of the arg string is not allowed to exceed 1024 bytes.  If the arg given\n\
90 is an integer or if none is specified, the result value is an integer\n\
91 corresponding to the return value of the fcntl call in the C code.");
92 
93 
94 /* ioctl(fd, op, [arg]) */
95 
96 static PyObject *
fcntl_ioctl(PyObject * self,PyObject * args)97 fcntl_ioctl(PyObject *self, PyObject *args)
98 {
99 #define IOCTL_BUFSZ 1024
100     int fd;
101     /* In PyArg_ParseTuple below, we use the unsigned non-checked 'I'
102        format for the 'code' parameter because Python turns 0x8000000
103        into either a large positive number (PyLong or PyInt on 64-bit
104        platforms) or a negative number on others (32-bit PyInt)
105        whereas the system expects it to be a 32bit bit field value
106        regardless of it being passed as an int or unsigned long on
107        various platforms.  See the termios.TIOCSWINSZ constant across
108        platforms for an example of this.
109 
110        If any of the 64bit platforms ever decide to use more than 32bits
111        in their unsigned long ioctl codes this will break and need
112        special casing based on the platform being built on.
113      */
114     unsigned int code;
115     int arg;
116     int ret;
117     char *str;
118     Py_ssize_t len;
119     int mutate_arg = 1;
120     char buf[IOCTL_BUFSZ+1];  /* argument plus NUL byte */
121 
122     if (PyArg_ParseTuple(args, "O&Iw#|i:ioctl",
123                          conv_descriptor, &fd, &code,
124                          &str, &len, &mutate_arg)) {
125         char *arg;
126 
127         if (mutate_arg) {
128             if (len <= IOCTL_BUFSZ) {
129                 memcpy(buf, str, len);
130                 buf[len] = '\0';
131                 arg = buf;
132             }
133             else {
134                 arg = str;
135             }
136         }
137         else {
138             if (len > IOCTL_BUFSZ) {
139                 PyErr_SetString(PyExc_ValueError,
140                     "ioctl string arg too long");
141                 return NULL;
142             }
143             else {
144                 memcpy(buf, str, len);
145                 buf[len] = '\0';
146                 arg = buf;
147             }
148         }
149         if (buf == arg) {
150             Py_BEGIN_ALLOW_THREADS /* think array.resize() */
151             ret = ioctl(fd, code, arg);
152             Py_END_ALLOW_THREADS
153         }
154         else {
155             ret = ioctl(fd, code, arg);
156         }
157         if (mutate_arg && (len <= IOCTL_BUFSZ)) {
158             memcpy(str, buf, len);
159         }
160         if (ret < 0) {
161             PyErr_SetFromErrno(PyExc_IOError);
162             return NULL;
163         }
164         if (mutate_arg) {
165             return PyInt_FromLong(ret);
166         }
167         else {
168             return PyString_FromStringAndSize(buf, len);
169         }
170     }
171 
172     PyErr_Clear();
173     if (PyArg_ParseTuple(args, "O&Is#:ioctl",
174                          conv_descriptor, &fd, &code, &str, &len)) {
175         if (len > IOCTL_BUFSZ) {
176             PyErr_SetString(PyExc_ValueError,
177                             "ioctl string arg too long");
178             return NULL;
179         }
180         memcpy(buf, str, len);
181         buf[len] = '\0';
182         Py_BEGIN_ALLOW_THREADS
183         ret = ioctl(fd, code, buf);
184         Py_END_ALLOW_THREADS
185         if (ret < 0) {
186             PyErr_SetFromErrno(PyExc_IOError);
187             return NULL;
188         }
189         return PyString_FromStringAndSize(buf, len);
190     }
191 
192     PyErr_Clear();
193     arg = 0;
194     if (!PyArg_ParseTuple(args,
195          "O&I|i;ioctl requires a file or file descriptor,"
196          " an integer and optionally an integer or buffer argument",
197                           conv_descriptor, &fd, &code, &arg)) {
198       return NULL;
199     }
200     Py_BEGIN_ALLOW_THREADS
201 #ifdef __VMS
202     ret = ioctl(fd, code, (void *)arg);
203 #else
204     ret = ioctl(fd, code, arg);
205 #endif
206     Py_END_ALLOW_THREADS
207     if (ret < 0) {
208         PyErr_SetFromErrno(PyExc_IOError);
209         return NULL;
210     }
211     return PyInt_FromLong((long)ret);
212 #undef IOCTL_BUFSZ
213 }
214 
215 PyDoc_STRVAR(ioctl_doc,
216 "ioctl(fd, op[, arg[, mutate_flag]])\n\
217 \n\
218 Perform the operation op on file descriptor fd.  The values used for op\n\
219 are operating system dependent, and are available as constants in the\n\
220 fcntl or termios library modules, using the same names as used in the\n\
221 relevant C header files.\n\
222 \n\
223 The argument arg is optional, and defaults to 0; it may be an int or a\n\
224 buffer containing character data (most likely a string or an array). \n\
225 \n\
226 If the argument is a mutable buffer (such as an array) and if the\n\
227 mutate_flag argument (which is only allowed in this case) is true then the\n\
228 buffer is (in effect) passed to the operating system and changes made by\n\
229 the OS will be reflected in the contents of the buffer after the call has\n\
230 returned.  The return value is the integer returned by the ioctl system\n\
231 call.\n\
232 \n\
233 If the argument is a mutable buffer and the mutable_flag argument is not\n\
234 passed or is false, the behavior is as if a string had been passed.  This\n\
235 behavior will change in future releases of Python.\n\
236 \n\
237 If the argument is an immutable buffer (most likely a string) then a copy\n\
238 of the buffer is passed to the operating system and the return value is a\n\
239 string of the same length containing whatever the operating system put in\n\
240 the buffer.  The length of the arg buffer in this case is not allowed to\n\
241 exceed 1024 bytes.\n\
242 \n\
243 If the arg given is an integer or if none is specified, the result value is\n\
244 an integer corresponding to the return value of the ioctl call in the C\n\
245 code.");
246 
247 
248 /* flock(fd, operation) */
249 
250 static PyObject *
fcntl_flock(PyObject * self,PyObject * args)251 fcntl_flock(PyObject *self, PyObject *args)
252 {
253     int fd;
254     int code;
255     int ret;
256 
257     if (!PyArg_ParseTuple(args, "O&i:flock",
258                           conv_descriptor, &fd, &code))
259         return NULL;
260 
261 #ifdef HAVE_FLOCK
262     Py_BEGIN_ALLOW_THREADS
263     ret = flock(fd, code);
264     Py_END_ALLOW_THREADS
265 #else
266 
267 #ifndef LOCK_SH
268 #define LOCK_SH         1       /* shared lock */
269 #define LOCK_EX         2       /* exclusive lock */
270 #define LOCK_NB         4       /* don't block when locking */
271 #define LOCK_UN         8       /* unlock */
272 #endif
273     {
274         struct flock l;
275         if (code == LOCK_UN)
276             l.l_type = F_UNLCK;
277         else if (code & LOCK_SH)
278             l.l_type = F_RDLCK;
279         else if (code & LOCK_EX)
280             l.l_type = F_WRLCK;
281         else {
282             PyErr_SetString(PyExc_ValueError,
283                             "unrecognized flock argument");
284             return NULL;
285         }
286         l.l_whence = l.l_start = l.l_len = 0;
287         Py_BEGIN_ALLOW_THREADS
288         ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
289         Py_END_ALLOW_THREADS
290     }
291 #endif /* HAVE_FLOCK */
292     if (ret < 0) {
293         PyErr_SetFromErrno(PyExc_IOError);
294         return NULL;
295     }
296     Py_INCREF(Py_None);
297     return Py_None;
298 }
299 
300 PyDoc_STRVAR(flock_doc,
301 "flock(fd, operation)\n\
302 \n\
303 Perform the lock operation op on file descriptor fd.  See the Unix \n\
304 manual page for flock(2) for details.  (On some systems, this function is\n\
305 emulated using fcntl().)");
306 
307 
308 /* lockf(fd, operation) */
309 static PyObject *
fcntl_lockf(PyObject * self,PyObject * args)310 fcntl_lockf(PyObject *self, PyObject *args)
311 {
312     int fd, code, ret, whence = 0;
313     PyObject *lenobj = NULL, *startobj = NULL;
314 
315     if (!PyArg_ParseTuple(args, "O&i|OOi:lockf",
316                           conv_descriptor, &fd, &code,
317                           &lenobj, &startobj, &whence))
318         return NULL;
319 
320 #if defined(PYOS_OS2) && defined(PYCC_GCC)
321     PyErr_SetString(PyExc_NotImplementedError,
322                     "lockf not supported on OS/2 (EMX)");
323     return NULL;
324 #else
325 #ifndef LOCK_SH
326 #define LOCK_SH         1       /* shared lock */
327 #define LOCK_EX         2       /* exclusive lock */
328 #define LOCK_NB         4       /* don't block when locking */
329 #define LOCK_UN         8       /* unlock */
330 #endif  /* LOCK_SH */
331     {
332         struct flock l;
333         if (code == LOCK_UN)
334             l.l_type = F_UNLCK;
335         else if (code & LOCK_SH)
336             l.l_type = F_RDLCK;
337         else if (code & LOCK_EX)
338             l.l_type = F_WRLCK;
339         else {
340             PyErr_SetString(PyExc_ValueError,
341                             "unrecognized lockf argument");
342             return NULL;
343         }
344         l.l_start = l.l_len = 0;
345         if (startobj != NULL) {
346 #if !defined(HAVE_LARGEFILE_SUPPORT)
347             l.l_start = PyInt_AsLong(startobj);
348 #else
349             l.l_start = PyLong_Check(startobj) ?
350                             PyLong_AsLongLong(startobj) :
351                     PyInt_AsLong(startobj);
352 #endif
353             if (PyErr_Occurred())
354                 return NULL;
355         }
356         if (lenobj != NULL) {
357 #if !defined(HAVE_LARGEFILE_SUPPORT)
358             l.l_len = PyInt_AsLong(lenobj);
359 #else
360             l.l_len = PyLong_Check(lenobj) ?
361                             PyLong_AsLongLong(lenobj) :
362                     PyInt_AsLong(lenobj);
363 #endif
364             if (PyErr_Occurred())
365                 return NULL;
366         }
367         l.l_whence = whence;
368         Py_BEGIN_ALLOW_THREADS
369         ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
370         Py_END_ALLOW_THREADS
371     }
372     if (ret < 0) {
373         PyErr_SetFromErrno(PyExc_IOError);
374         return NULL;
375     }
376     Py_INCREF(Py_None);
377     return Py_None;
378 #endif  /* defined(PYOS_OS2) && defined(PYCC_GCC) */
379 }
380 
381 PyDoc_STRVAR(lockf_doc,
382 "lockf (fd, operation, length=0, start=0, whence=0)\n\
383 \n\
384 This is essentially a wrapper around the fcntl() locking calls.  fd is the\n\
385 file descriptor of the file to lock or unlock, and operation is one of the\n\
386 following values:\n\
387 \n\
388     LOCK_UN - unlock\n\
389     LOCK_SH - acquire a shared lock\n\
390     LOCK_EX - acquire an exclusive lock\n\
391 \n\
392 When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n\
393 LOCK_NB to avoid blocking on lock acquisition.  If LOCK_NB is used and the\n\
394 lock cannot be acquired, an IOError will be raised and the exception will\n\
395 have an errno attribute set to EACCES or EAGAIN (depending on the operating\n\
396 system -- for portability, check for either value).\n\
397 \n\
398 length is the number of bytes to lock, with the default meaning to lock to\n\
399 EOF.  start is the byte offset, relative to whence, to that the lock\n\
400 starts.  whence is as with fileobj.seek(), specifically:\n\
401 \n\
402     0 - relative to the start of the file (SEEK_SET)\n\
403     1 - relative to the current buffer position (SEEK_CUR)\n\
404     2 - relative to the end of the file (SEEK_END)");
405 
406 /* List of functions */
407 
408 static PyMethodDef fcntl_methods[] = {
409     {"fcntl",           fcntl_fcntl, METH_VARARGS, fcntl_doc},
410     {"ioctl",           fcntl_ioctl, METH_VARARGS, ioctl_doc},
411     {"flock",           fcntl_flock, METH_VARARGS, flock_doc},
412     {"lockf",       fcntl_lockf, METH_VARARGS, lockf_doc},
413     {NULL,              NULL}           /* sentinel */
414 };
415 
416 
417 PyDoc_STRVAR(module_doc,
418 "This module performs file control and I/O control on file \n\
419 descriptors.  It is an interface to the fcntl() and ioctl() Unix\n\
420 routines.  File descriptors can be obtained with the fileno() method of\n\
421 a file or socket object.");
422 
423 /* Module initialisation */
424 
425 static int
ins(PyObject * d,char * symbol,long value)426 ins(PyObject* d, char* symbol, long value)
427 {
428     PyObject* v = PyInt_FromLong(value);
429     if (!v || PyDict_SetItemString(d, symbol, v) < 0)
430         return -1;
431 
432     Py_DECREF(v);
433     return 0;
434 }
435 
436 #define INS(x) if (ins(d, #x, (long)x)) return -1
437 
438 static int
all_ins(PyObject * d)439 all_ins(PyObject* d)
440 {
441     if (ins(d, "LOCK_SH", (long)LOCK_SH)) return -1;
442     if (ins(d, "LOCK_EX", (long)LOCK_EX)) return -1;
443     if (ins(d, "LOCK_NB", (long)LOCK_NB)) return -1;
444     if (ins(d, "LOCK_UN", (long)LOCK_UN)) return -1;
445 /* GNU extensions, as of glibc 2.2.4 */
446 #ifdef LOCK_MAND
447     if (ins(d, "LOCK_MAND", (long)LOCK_MAND)) return -1;
448 #endif
449 #ifdef LOCK_READ
450     if (ins(d, "LOCK_READ", (long)LOCK_READ)) return -1;
451 #endif
452 #ifdef LOCK_WRITE
453     if (ins(d, "LOCK_WRITE", (long)LOCK_WRITE)) return -1;
454 #endif
455 #ifdef LOCK_RW
456     if (ins(d, "LOCK_RW", (long)LOCK_RW)) return -1;
457 #endif
458 
459 #ifdef F_DUPFD
460     if (ins(d, "F_DUPFD", (long)F_DUPFD)) return -1;
461 #endif
462 #ifdef F_GETFD
463     if (ins(d, "F_GETFD", (long)F_GETFD)) return -1;
464 #endif
465 #ifdef F_SETFD
466     if (ins(d, "F_SETFD", (long)F_SETFD)) return -1;
467 #endif
468 #ifdef F_GETFL
469     if (ins(d, "F_GETFL", (long)F_GETFL)) return -1;
470 #endif
471 #ifdef F_SETFL
472     if (ins(d, "F_SETFL", (long)F_SETFL)) return -1;
473 #endif
474 #ifdef F_GETLK
475     if (ins(d, "F_GETLK", (long)F_GETLK)) return -1;
476 #endif
477 #ifdef F_SETLK
478     if (ins(d, "F_SETLK", (long)F_SETLK)) return -1;
479 #endif
480 #ifdef F_SETLKW
481     if (ins(d, "F_SETLKW", (long)F_SETLKW)) return -1;
482 #endif
483 #ifdef F_GETOWN
484     if (ins(d, "F_GETOWN", (long)F_GETOWN)) return -1;
485 #endif
486 #ifdef F_SETOWN
487     if (ins(d, "F_SETOWN", (long)F_SETOWN)) return -1;
488 #endif
489 #ifdef F_GETSIG
490     if (ins(d, "F_GETSIG", (long)F_GETSIG)) return -1;
491 #endif
492 #ifdef F_SETSIG
493     if (ins(d, "F_SETSIG", (long)F_SETSIG)) return -1;
494 #endif
495 #ifdef F_RDLCK
496     if (ins(d, "F_RDLCK", (long)F_RDLCK)) return -1;
497 #endif
498 #ifdef F_WRLCK
499     if (ins(d, "F_WRLCK", (long)F_WRLCK)) return -1;
500 #endif
501 #ifdef F_UNLCK
502     if (ins(d, "F_UNLCK", (long)F_UNLCK)) return -1;
503 #endif
504 /* LFS constants */
505 #ifdef F_GETLK64
506     if (ins(d, "F_GETLK64", (long)F_GETLK64)) return -1;
507 #endif
508 #ifdef F_SETLK64
509     if (ins(d, "F_SETLK64", (long)F_SETLK64)) return -1;
510 #endif
511 #ifdef F_SETLKW64
512     if (ins(d, "F_SETLKW64", (long)F_SETLKW64)) return -1;
513 #endif
514 /* GNU extensions, as of glibc 2.2.4. */
515 #ifdef FASYNC
516     if (ins(d, "FASYNC", (long)FASYNC)) return -1;
517 #endif
518 #ifdef F_SETLEASE
519     if (ins(d, "F_SETLEASE", (long)F_SETLEASE)) return -1;
520 #endif
521 #ifdef F_GETLEASE
522     if (ins(d, "F_GETLEASE", (long)F_GETLEASE)) return -1;
523 #endif
524 #ifdef F_NOTIFY
525     if (ins(d, "F_NOTIFY", (long)F_NOTIFY)) return -1;
526 #endif
527 /* Old BSD flock(). */
528 #ifdef F_EXLCK
529     if (ins(d, "F_EXLCK", (long)F_EXLCK)) return -1;
530 #endif
531 #ifdef F_SHLCK
532     if (ins(d, "F_SHLCK", (long)F_SHLCK)) return -1;
533 #endif
534 
535 /* OS X (and maybe others) let you tell the storage device to flush to physical media */
536 #ifdef F_FULLFSYNC
537     if (ins(d, "F_FULLFSYNC", (long)F_FULLFSYNC)) return -1;
538 #endif
539 
540 /* For F_{GET|SET}FL */
541 #ifdef FD_CLOEXEC
542     if (ins(d, "FD_CLOEXEC", (long)FD_CLOEXEC)) return -1;
543 #endif
544 
545 /* For F_NOTIFY */
546 #ifdef DN_ACCESS
547     if (ins(d, "DN_ACCESS", (long)DN_ACCESS)) return -1;
548 #endif
549 #ifdef DN_MODIFY
550     if (ins(d, "DN_MODIFY", (long)DN_MODIFY)) return -1;
551 #endif
552 #ifdef DN_CREATE
553     if (ins(d, "DN_CREATE", (long)DN_CREATE)) return -1;
554 #endif
555 #ifdef DN_DELETE
556     if (ins(d, "DN_DELETE", (long)DN_DELETE)) return -1;
557 #endif
558 #ifdef DN_RENAME
559     if (ins(d, "DN_RENAME", (long)DN_RENAME)) return -1;
560 #endif
561 #ifdef DN_ATTRIB
562     if (ins(d, "DN_ATTRIB", (long)DN_ATTRIB)) return -1;
563 #endif
564 #ifdef DN_MULTISHOT
565     if (ins(d, "DN_MULTISHOT", (long)DN_MULTISHOT)) return -1;
566 #endif
567 
568 #ifdef HAVE_STROPTS_H
569     /* Unix 98 guarantees that these are in stropts.h. */
570     INS(I_PUSH);
571     INS(I_POP);
572     INS(I_LOOK);
573     INS(I_FLUSH);
574     INS(I_FLUSHBAND);
575     INS(I_SETSIG);
576     INS(I_GETSIG);
577     INS(I_FIND);
578     INS(I_PEEK);
579     INS(I_SRDOPT);
580     INS(I_GRDOPT);
581     INS(I_NREAD);
582     INS(I_FDINSERT);
583     INS(I_STR);
584     INS(I_SWROPT);
585 #ifdef I_GWROPT
586     /* despite the comment above, old-ish glibcs miss a couple... */
587     INS(I_GWROPT);
588 #endif
589     INS(I_SENDFD);
590     INS(I_RECVFD);
591     INS(I_LIST);
592     INS(I_ATMARK);
593     INS(I_CKBAND);
594     INS(I_GETBAND);
595     INS(I_CANPUT);
596     INS(I_SETCLTIME);
597 #ifdef I_GETCLTIME
598     INS(I_GETCLTIME);
599 #endif
600     INS(I_LINK);
601     INS(I_UNLINK);
602     INS(I_PLINK);
603     INS(I_PUNLINK);
604 #endif
605 
606     return 0;
607 }
608 
609 PyMODINIT_FUNC
initfcntl(void)610 initfcntl(void)
611 {
612     PyObject *m, *d;
613 
614     /* Create the module and add the functions and documentation */
615     m = Py_InitModule3("fcntl", fcntl_methods, module_doc);
616     if (m == NULL)
617         return;
618 
619     /* Add some symbolic constants to the module */
620     d = PyModule_GetDict(m);
621     all_ins(d);
622 }
623