fcntlmodule.c revision cdc445122208cb90a59a468a7396b227e223c43a
1
2/* fcntl module */
3
4#include "Python.h"
5
6#ifdef HAVE_SYS_FILE_H
7#include <sys/file.h>
8#endif
9
10#include <sys/ioctl.h>
11#include <fcntl.h>
12
13
14static int
15conv_descriptor(PyObject *object, int *target)
16{
17    int fd = PyObject_AsFileDescriptor(object);
18
19    if (fd < 0)
20        return 0;
21    *target = fd;
22    return 1;
23}
24
25
26/* fcntl(fd, opt, [arg]) */
27
28static PyObject *
29fcntl_fcntl(PyObject *self, PyObject *args)
30{
31	int fd;
32	int code;
33	int arg;
34	int ret;
35	char *str;
36	int len;
37	char buf[1024];
38
39	if (PyArg_ParseTuple(args, "O&is#:fcntl",
40                             conv_descriptor, &fd, &code, &str, &len)) {
41		if (len > sizeof buf) {
42			PyErr_SetString(PyExc_ValueError,
43					"fcntl string arg too long");
44			return NULL;
45		}
46		memcpy(buf, str, len);
47		Py_BEGIN_ALLOW_THREADS
48		ret = fcntl(fd, code, buf);
49		Py_END_ALLOW_THREADS
50		if (ret < 0) {
51			PyErr_SetFromErrno(PyExc_IOError);
52			return NULL;
53		}
54		return PyString_FromStringAndSize(buf, len);
55	}
56
57	PyErr_Clear();
58	arg = 0;
59	if (!PyArg_ParseTuple(args,
60             "O&i|i;fcntl requires a file or file descriptor,"
61             " an integer and optionally a third integer or a string",
62			      conv_descriptor, &fd, &code, &arg)) {
63	  return NULL;
64	}
65	Py_BEGIN_ALLOW_THREADS
66	ret = fcntl(fd, code, arg);
67	Py_END_ALLOW_THREADS
68	if (ret < 0) {
69		PyErr_SetFromErrno(PyExc_IOError);
70		return NULL;
71	}
72	return PyInt_FromLong((long)ret);
73}
74
75static char fcntl_doc [] =
76
77"fcntl(fd, opt, [arg])\n\
78\n\
79Perform the requested operation on file descriptor fd.  The operation\n\
80is defined by op and is operating system dependent.  These constants are\n\
81available from the fcntl module.  The argument arg is optional, and\n\
82defaults to 0; it may be an int or a string. If arg is given as a string,\n\
83the return value of fcntl is a string of that length, containing the\n\
84resulting value put in the arg buffer by the operating system.The length\n\
85of the arg string is not allowed to exceed 1024 bytes. If the arg given\n\
86is an integer or if none is specified, the result value is an integer\n\
87corresponding to the return value of the fcntl call in the C code.";
88
89
90/* ioctl(fd, opt, [arg]) */
91
92static PyObject *
93fcntl_ioctl(PyObject *self, PyObject *args)
94{
95	int fd;
96	int code;
97	int arg;
98	int ret;
99	char *str;
100	int len;
101	char buf[1024];
102
103	if (PyArg_ParseTuple(args, "O&is#:ioctl",
104                             conv_descriptor, &fd, &code, &str, &len)) {
105		if (len > sizeof buf) {
106			PyErr_SetString(PyExc_ValueError,
107					"ioctl string arg too long");
108			return NULL;
109		}
110		memcpy(buf, str, len);
111		Py_BEGIN_ALLOW_THREADS
112		ret = ioctl(fd, code, buf);
113		Py_END_ALLOW_THREADS
114		if (ret < 0) {
115			PyErr_SetFromErrno(PyExc_IOError);
116			return NULL;
117		}
118		return PyString_FromStringAndSize(buf, len);
119	}
120
121	PyErr_Clear();
122	arg = 0;
123	if (!PyArg_ParseTuple(args,
124	     "O&i|i;ioctl requires a file or file descriptor,"
125	     " an integer and optionally a third integer or a string",
126			      conv_descriptor, &fd, &code, &arg)) {
127	  return NULL;
128	}
129	Py_BEGIN_ALLOW_THREADS
130	ret = ioctl(fd, code, arg);
131	Py_END_ALLOW_THREADS
132	if (ret < 0) {
133		PyErr_SetFromErrno(PyExc_IOError);
134		return NULL;
135	}
136	return PyInt_FromLong((long)ret);
137}
138
139static char ioctl_doc [] =
140"ioctl(fd, opt, [arg])\n\
141\n\
142Perform the requested operation on file descriptor fd.  The operation\n\
143is defined by op and is operating system dependent.  Typically these\n\
144codes can be retrieved from the library module IOCTL.  The argument arg\n\
145is optional, and defaults to 0; it may be an int or a string. If arg is\n\
146given as a string, the return value of ioctl is a string of that length,\n\
147containing the resulting value put in the arg buffer by the operating system.\n\
148The length of the arg string is not allowed to exceed 1024 bytes. If the arg\n\
149given is an integer or if none is specified, the result value is an integer\n\
150corresponding to the return value of the ioctl call in the C code.";
151
152
153/* flock(fd, operation) */
154
155static PyObject *
156fcntl_flock(PyObject *self, PyObject *args)
157{
158	int fd;
159	int code;
160	int ret;
161
162	if (!PyArg_ParseTuple(args, "O&i:flock",
163                              conv_descriptor, &fd, &code))
164		return NULL;
165
166#ifdef HAVE_FLOCK
167	Py_BEGIN_ALLOW_THREADS
168	ret = flock(fd, code);
169	Py_END_ALLOW_THREADS
170#else
171
172#ifndef LOCK_SH
173#define LOCK_SH		1	/* shared lock */
174#define LOCK_EX		2	/* exclusive lock */
175#define LOCK_NB		4	/* don't block when locking */
176#define LOCK_UN		8	/* unlock */
177#endif
178	{
179		struct flock l;
180		if (code == LOCK_UN)
181			l.l_type = F_UNLCK;
182		else if (code & LOCK_SH)
183			l.l_type = F_RDLCK;
184		else if (code & LOCK_EX)
185			l.l_type = F_WRLCK;
186		else {
187			PyErr_SetString(PyExc_ValueError,
188					"unrecognized flock argument");
189			return NULL;
190		}
191		l.l_whence = l.l_start = l.l_len = 0;
192		Py_BEGIN_ALLOW_THREADS
193		ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
194		Py_END_ALLOW_THREADS
195	}
196#endif /* HAVE_FLOCK */
197	if (ret < 0) {
198		PyErr_SetFromErrno(PyExc_IOError);
199		return NULL;
200	}
201	Py_INCREF(Py_None);
202	return Py_None;
203}
204
205static char flock_doc [] =
206"flock(fd, operation)\n\
207\n\
208Perform the lock operation op on file descriptor fd.  See the Unix \n\
209manual flock(3) for details.  (On some systems, this function is\n\
210emulated using fcntl().)";
211
212
213/* lockf(fd, operation) */
214static PyObject *
215fcntl_lockf(PyObject *self, PyObject *args)
216{
217	int fd, code, ret, whence = 0;
218	PyObject *lenobj = NULL, *startobj = NULL;
219
220	if (!PyArg_ParseTuple(args, "O&i|OOi:lockf",
221                              conv_descriptor, &fd, &code,
222			      &lenobj, &startobj, &whence))
223	    return NULL;
224
225#ifndef LOCK_SH
226#define LOCK_SH		1	/* shared lock */
227#define LOCK_EX		2	/* exclusive lock */
228#define LOCK_NB		4	/* don't block when locking */
229#define LOCK_UN		8	/* unlock */
230#endif
231	{
232		struct flock l;
233		if (code == LOCK_UN)
234			l.l_type = F_UNLCK;
235		else if (code & LOCK_SH)
236			l.l_type = F_RDLCK;
237		else if (code & LOCK_EX)
238			l.l_type = F_WRLCK;
239		else {
240			PyErr_SetString(PyExc_ValueError,
241					"unrecognized flock argument");
242			return NULL;
243		}
244		l.l_start = l.l_len = 0;
245		if (startobj != NULL) {
246#if !defined(HAVE_LARGEFILE_SUPPORT)
247			l.l_start = PyInt_AsLong(startobj);
248#else
249			l.l_start = PyLong_Check(startobj) ?
250					PyLong_AsLongLong(startobj) :
251					PyInt_AsLong(startobj);
252#endif
253			if (PyErr_Occurred())
254				return NULL;
255		}
256		if (lenobj != NULL) {
257#if !defined(HAVE_LARGEFILE_SUPPORT)
258			l.l_len = PyInt_AsLong(lenobj);
259#else
260			l.l_len = PyLong_Check(lenobj) ?
261					PyLong_AsLongLong(lenobj) :
262					PyInt_AsLong(lenobj);
263#endif
264			if (PyErr_Occurred())
265				return NULL;
266		}
267		l.l_whence = whence;
268		Py_BEGIN_ALLOW_THREADS
269		ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
270		Py_END_ALLOW_THREADS
271	}
272	if (ret < 0) {
273		PyErr_SetFromErrno(PyExc_IOError);
274		return NULL;
275	}
276	Py_INCREF(Py_None);
277	return Py_None;
278}
279
280static char lockf_doc [] =
281"lockf (fd, operation, length=0, start=0, whence=0)\n\
282\n\
283This is essentially a wrapper around the fcntl() locking calls.  fd is the\n\
284file descriptor of the file to lock or unlock, and operation is one of the\n\
285following values:\n\
286\n\
287    LOCK_UN - unlock\n\
288    LOCK_SH - acquire a shared lock\n\
289    LOCK_EX - acquire an exclusive lock\n\
290\n\
291When operation is LOCK_SH or LOCK_EX, it can also be bit-wise OR'd with\n\
292LOCK_NB to avoid blocking on lock acquisition.  If LOCK_NB is used and the\n\
293lock cannot be acquired, an IOError will be raised and the exception will\n\
294have an errno attribute set to EACCES or EAGAIN (depending on the operating\n\
295system -- for portability, check for either value).\n\
296\n\
297length is the number of bytes to lock, with the default meaning to lock to\n\
298EOF.  start is the byte offset, relative to whence, to that the lock\n\
299starts.  whence is as with fileobj.seek(), specifically:\n\
300\n\
301    0 - relative to the start of the file (SEEK_SET)\n\
302    1 - relative to the current buffer position (SEEK_CUR)\n\
303    2 - relative to the end of the file (SEEK_END)";
304
305/* List of functions */
306
307static PyMethodDef fcntl_methods[] = {
308	{"fcntl",	fcntl_fcntl, METH_VARARGS, fcntl_doc},
309	{"ioctl",	fcntl_ioctl, METH_VARARGS, ioctl_doc},
310	{"flock",	fcntl_flock, METH_VARARGS, flock_doc},
311	{"lockf",       fcntl_lockf, METH_VARARGS, lockf_doc},
312	{NULL,		NULL}		/* sentinel */
313};
314
315
316static char module_doc [] =
317
318"This module performs file control and I/O control on file \n\
319descriptors.  It is an interface to the fcntl() and ioctl() Unix\n\
320routines.  File descriptors can be obtained with the fileno() method of\n\
321a file or socket object.";
322
323/* Module initialisation */
324
325static int
326ins(PyObject* d, char* symbol, long value)
327{
328        PyObject* v = PyInt_FromLong(value);
329        if (!v || PyDict_SetItemString(d, symbol, v) < 0)
330                return -1;
331
332        Py_DECREF(v);
333        return 0;
334}
335
336static int
337all_ins(PyObject* d)
338{
339        if (ins(d, "LOCK_SH", (long)LOCK_SH)) return -1;
340        if (ins(d, "LOCK_EX", (long)LOCK_EX)) return -1;
341        if (ins(d, "LOCK_NB", (long)LOCK_NB)) return -1;
342        if (ins(d, "LOCK_UN", (long)LOCK_UN)) return -1;
343/* GNU extensions, as of glibc 2.2.4 */
344#ifdef LOCK_MAND
345        if (ins(d, "LOCK_MAND", (long)LOCK_MAND)) return -1;
346#endif
347#ifdef LOCK_READ
348        if (ins(d, "LOCK_READ", (long)LOCK_READ)) return -1;
349#endif
350#ifdef LOCK_WRITE
351        if (ins(d, "LOCK_WRITE", (long)LOCK_WRITE)) return -1;
352#endif
353#ifdef LOCK_RW
354        if (ins(d, "LOCK_RW", (long)LOCK_RW)) return -1;
355#endif
356
357#ifdef F_DUPFD
358        if (ins(d, "F_DUPFD", (long)F_DUPFD)) return -1;
359#endif
360#ifdef F_GETFD
361        if (ins(d, "F_GETFD", (long)F_GETFD)) return -1;
362#endif
363#ifdef F_SETFD
364        if (ins(d, "F_SETFD", (long)F_SETFD)) return -1;
365#endif
366#ifdef F_GETFL
367        if (ins(d, "F_GETFL", (long)F_GETFL)) return -1;
368#endif
369#ifdef F_SETFL
370        if (ins(d, "F_SETFL", (long)F_SETFL)) return -1;
371#endif
372#ifdef F_GETLK
373        if (ins(d, "F_GETLK", (long)F_GETLK)) return -1;
374#endif
375#ifdef F_SETLK
376        if (ins(d, "F_SETLK", (long)F_SETLK)) return -1;
377#endif
378#ifdef F_SETLKW
379        if (ins(d, "F_SETLKW", (long)F_SETLKW)) return -1;
380#endif
381#ifdef F_GETOWN
382        if (ins(d, "F_GETOWN", (long)F_GETOWN)) return -1;
383#endif
384#ifdef F_SETOWN
385        if (ins(d, "F_SETOWN", (long)F_SETOWN)) return -1;
386#endif
387#ifdef F_GETSIG
388        if (ins(d, "F_GETSIG", (long)F_GETSIG)) return -1;
389#endif
390#ifdef F_SETSIG
391        if (ins(d, "F_SETSIG", (long)F_SETSIG)) return -1;
392#endif
393#ifdef F_RDLCK
394        if (ins(d, "F_RDLCK", (long)F_RDLCK)) return -1;
395#endif
396#ifdef F_WRLCK
397        if (ins(d, "F_WRLCK", (long)F_WRLCK)) return -1;
398#endif
399#ifdef F_UNLCK
400        if (ins(d, "F_UNLCK", (long)F_UNLCK)) return -1;
401#endif
402/* LFS constants */
403#ifdef F_GETLK64
404        if (ins(d, "F_GETLK64", (long)F_GETLK64)) return -1;
405#endif
406#ifdef F_SETLK64
407        if (ins(d, "F_SETLK64", (long)F_SETLK64)) return -1;
408#endif
409#ifdef F_SETLKW64
410        if (ins(d, "F_SETLKW64", (long)F_SETLKW64)) return -1;
411#endif
412/* GNU extensions, as of glibc 2.2.4. */
413#ifdef F_SETLEASE
414        if (ins(d, "F_SETLEASE", (long)F_SETLEASE)) return -1;
415#endif
416#ifdef F_GETLEASE
417        if (ins(d, "F_GETLEASE", (long)F_GETLEASE)) return -1;
418#endif
419#ifdef F_NOTIFY
420        if (ins(d, "F_NOTIFY", (long)F_NOTIFY)) return -1;
421#endif
422/* Old BSD flock(). */
423#ifdef F_EXLCK
424        if (ins(d, "F_EXLCK", (long)F_EXLCK)) return -1;
425#endif
426#ifdef F_SHLCK
427        if (ins(d, "F_SHLCK", (long)F_SHLCK)) return -1;
428#endif
429
430/* For F_{GET|SET}FL */
431#ifdef FD_CLOEXEC
432        if (ins(d, "FD_CLOEXEC", (long)FD_CLOEXEC)) return -1;
433#endif
434
435/* For F_NOTIFY */
436#ifdef DN_ACCESS
437        if (ins(d, "DN_ACCESS", (long)DN_ACCESS)) return -1;
438#endif
439#ifdef DN_MODIFY
440        if (ins(d, "DN_MODIFY", (long)DN_MODIFY)) return -1;
441#endif
442#ifdef DN_CREATE
443        if (ins(d, "DN_CREATE", (long)DN_CREATE)) return -1;
444#endif
445#ifdef DN_DELETE
446        if (ins(d, "DN_DELETE", (long)DN_DELETE)) return -1;
447#endif
448#ifdef DN_RENAME
449        if (ins(d, "DN_RENAME", (long)DN_RENAME)) return -1;
450#endif
451#ifdef DN_ATTRIB
452        if (ins(d, "DN_ATTRIB", (long)DN_ATTRIB)) return -1;
453#endif
454#ifdef DN_MULTISHOT
455        if (ins(d, "DN_MULTISHOT", (long)DN_MULTISHOT)) return -1;
456#endif
457
458	return 0;
459}
460
461DL_EXPORT(void)
462initfcntl(void)
463{
464	PyObject *m, *d;
465
466	/* Create the module and add the functions and documentation */
467	m = Py_InitModule3("fcntl", fcntl_methods, module_doc);
468
469	/* Add some symbolic constants to the module */
470	d = PyModule_GetDict(m);
471	all_ins(d);
472}
473