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