diff -r c4a2d0538441 Modules/fcntlmodule.c --- a/Modules/fcntlmodule.c Tue Jan 21 03:10:01 2014 -0500 +++ b/Modules/fcntlmodule.c Tue Jan 21 10:19:09 2014 -0500 @@ -15,6 +15,11 @@ #include #endif +/*[clinic input] +module fcntl +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + static int conv_descriptor(PyObject *object, int *target) { @@ -27,47 +32,114 @@ } -/* fcntl(fd, op, [arg]) */ +/*[clinic input] +fcntl.fcntl + + fd: object(type='int', converter='conv_descriptor') + code: int + arg: object = NULL + / + +Perform the operation op on file descriptor fd. + +The values used for op are operating system dependent, and are available +as constants in the fcntl module, using the same names as used in +the relevant C header files. The argument arg is optional, and +defaults to 0; it may be an int or a string. If arg is given as a string, +the return value of fcntl is a string of that length, containing the +resulting value put in the arg buffer by the operating system. The length +of the arg string is not allowed to exceed 1024 bytes. If the arg given +is an integer or if none is specified, the result value is an integer +corresponding to the return value of the fcntl call in the C code. +[clinic start generated code]*/ + +PyDoc_STRVAR(fcntl_fcntl__doc__, +"fcntl(fd, code, arg=None)\n" +"Perform the operation op on file descriptor fd.\n" +"\n" +"The values used for op are operating system dependent, and are available\n" +"as constants in the fcntl module, using the same names as used in\n" +"the relevant C header files. The argument arg is optional, and\n" +"defaults to 0; it may be an int or a string. If arg is given as a string,\n" +"the return value of fcntl is a string of that length, containing the\n" +"resulting value put in the arg buffer by the operating system. The length\n" +"of the arg string is not allowed to exceed 1024 bytes. If the arg given\n" +"is an integer or if none is specified, the result value is an integer\n" +"corresponding to the return value of the fcntl call in the C code."); + +#define FCNTL_FCNTL_METHODDEF \ + {"fcntl", (PyCFunction)fcntl_fcntl, METH_VARARGS, fcntl_fcntl__doc__}, static PyObject * -fcntl_fcntl(PyObject *self, PyObject *args) +fcntl_fcntl_impl(PyModuleDef *module, int fd, int code, PyObject *arg); + +static PyObject * +fcntl_fcntl(PyModuleDef *module, PyObject *args) { + PyObject *return_value = NULL; int fd; int code; - long arg; + PyObject *arg = NULL; + + if (!PyArg_ParseTuple(args, + "O&i|O:fcntl", + conv_descriptor, &fd, &code, &arg)) + goto exit; + return_value = fcntl_fcntl_impl(module, fd, code, arg); + +exit: + return return_value; +} + +static PyObject * +fcntl_fcntl_impl(PyModuleDef *module, int fd, int code, PyObject *arg) +/*[clinic end generated code: checksum=c6aa92ae153d591d93726f6ad89ce3232c1d4029]*/ +{ + long long_arg = 0; int ret; char *str; Py_ssize_t len; char buf[1024]; + PyObject *optional_arg_tuple; - if (PyArg_ParseTuple(args, "O&is#:fcntl", - conv_descriptor, &fd, &code, &str, &len)) { - if (len > sizeof buf) { + if (arg != NULL) { + int parse_result; + // As the optional argument can be l or s#, need to use the magic of + // PyArg_ParseTuple() to do the right thing if the s# is needed. + optional_arg_tuple = PyTuple_Pack(1, arg); + + if (PyArg_ParseTuple(optional_arg_tuple, "s#", &str, &len)) { + Py_DECREF(optional_arg_tuple); + + if (len > sizeof buf) { PyErr_SetString(PyExc_ValueError, "fcntl string arg too long"); return NULL; + } + memcpy(buf, str, len); + Py_BEGIN_ALLOW_THREADS + ret = fcntl(fd, code, buf); + Py_END_ALLOW_THREADS + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyBytes_FromStringAndSize(buf, len); } - memcpy(buf, str, len); - Py_BEGIN_ALLOW_THREADS - ret = fcntl(fd, code, buf); - Py_END_ALLOW_THREADS - if (ret < 0) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - return PyBytes_FromStringAndSize(buf, len); + + PyErr_Clear(); + parse_result = PyArg_ParseTuple(optional_arg_tuple, + "l;fcntl requires a file or file descriptor," + " an integer and optionally a third integer or a string", + &long_arg); + Py_DECREF(optional_arg_tuple); + if (!parse_result) { + return NULL; + } } - PyErr_Clear(); - arg = 0; - if (!PyArg_ParseTuple(args, - "O&i|l;fcntl requires a file or file descriptor," - " an integer and optionally a third integer or a string", - conv_descriptor, &fd, &code, &arg)) { - return NULL; - } Py_BEGIN_ALLOW_THREADS - ret = fcntl(fd, code, arg); + ret = fcntl(fd, code, long_arg); Py_END_ALLOW_THREADS if (ret < 0) { PyErr_SetFromErrno(PyExc_IOError); @@ -76,20 +148,6 @@ return PyLong_FromLong((long)ret); } -PyDoc_STRVAR(fcntl_doc, -"fcntl(fd, op, [arg])\n\ -\n\ -Perform the operation op on file descriptor fd. The values used\n\ -for op are operating system dependent, and are available\n\ -as constants in the fcntl module, using the same names as used in\n\ -the relevant C header files. The argument arg is optional, and\n\ -defaults to 0; it may be an int or a string. If arg is given as a string,\n\ -the return value of fcntl is a string of that length, containing the\n\ -resulting value put in the arg buffer by the operating system. The length\n\ -of the arg string is not allowed to exceed 1024 bytes. If the arg given\n\ -is an integer or if none is specified, the result value is an integer\n\ -corresponding to the return value of the fcntl call in the C code."); - /* ioctl(fd, op, [arg]) */ @@ -251,19 +309,55 @@ code."); -/* flock(fd, operation) */ +/*[clinic input] +fcntl.flock + + fd: object(type='int', converter='conv_descriptor') + code: int + / + +Perform the lock operation op on file descriptor fd. + +See the Unix manual page for flock(2) for details (On some systems, this +function is emulated using fcntl()). +[clinic start generated code]*/ + +PyDoc_STRVAR(fcntl_flock__doc__, +"flock(fd, code)\n" +"Perform the lock operation op on file descriptor fd.\n" +"\n" +"See the Unix manual page for flock(2) for details (On some systems, this\n" +"function is emulated using fcntl())."); + +#define FCNTL_FLOCK_METHODDEF \ + {"flock", (PyCFunction)fcntl_flock, METH_VARARGS, fcntl_flock__doc__}, static PyObject * -fcntl_flock(PyObject *self, PyObject *args) +fcntl_flock_impl(PyModuleDef *module, int fd, int code); + +static PyObject * +fcntl_flock(PyModuleDef *module, PyObject *args) { + PyObject *return_value = NULL; int fd; int code; + + if (!PyArg_ParseTuple(args, + "O&i:flock", + conv_descriptor, &fd, &code)) + goto exit; + return_value = fcntl_flock_impl(module, fd, code); + +exit: + return return_value; +} + +static PyObject * +fcntl_flock_impl(PyModuleDef *module, int fd, int code) +/*[clinic end generated code: checksum=3a8b37cd71057c8418e6769e14edb27b173026bb]*/ +{ int ret; - if (!PyArg_ParseTuple(args, "O&i:flock", - conv_descriptor, &fd, &code)) - return NULL; - #ifdef HAVE_FLOCK Py_BEGIN_ALLOW_THREADS ret = flock(fd, code); @@ -299,29 +393,100 @@ PyErr_SetFromErrno(PyExc_IOError); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyDoc_STRVAR(flock_doc, -"flock(fd, operation)\n\ -\n\ -Perform the lock operation op on file descriptor fd. See the Unix \n\ -manual page for flock(2) for details. (On some systems, this function is\n\ -emulated using fcntl().)"); +/*[clinic input] +fcntl.lockf -/* lockf(fd, operation) */ + fd: object(type='int', converter='conv_descriptor') + code: int + lenobj: object = NULL + startobj: object = NULL + whence: int = 0 + / + +A wrapper around the fcntl() locking calls. + +fd is the file descriptor of the file to lock or unlock, and operation is one +of the following values: + + LOCK_UN - unlock + LOCK_SH - acquire a shared lock + LOCK_EX - acquire an exclusive lock + +When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with +LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the +lock cannot be acquired, an IOError will be raised and the exception will +have an errno attribute set to EACCES or EAGAIN (depending on the operating +system -- for portability, check for either value). + +length is the number of bytes to lock, with the default meaning to lock to +EOF. start is the byte offset, relative to whence, to that the lock +starts. whence is as with fileobj.seek(), specifically: + + 0 - relative to the start of the file (SEEK_SET) + 1 - relative to the current buffer position (SEEK_CUR) + 2 - relative to the end of the file (SEEK_END) +[clinic start generated code]*/ + +PyDoc_STRVAR(fcntl_lockf__doc__, +"lockf(fd, code, lenobj=None, startobj=None, whence=0)\n" +"A wrapper around the fcntl() locking calls.\n" +"\n" +"fd is the file descriptor of the file to lock or unlock, and operation is one\n" +"of the following values:\n" +"\n" +" LOCK_UN - unlock\n" +" LOCK_SH - acquire a shared lock\n" +" LOCK_EX - acquire an exclusive lock\n" +"\n" +"When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n" +"LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the\n" +"lock cannot be acquired, an IOError will be raised and the exception will\n" +"have an errno attribute set to EACCES or EAGAIN (depending on the operating\n" +"system -- for portability, check for either value).\n" +"\n" +"length is the number of bytes to lock, with the default meaning to lock to\n" +"EOF. start is the byte offset, relative to whence, to that the lock\n" +"starts. whence is as with fileobj.seek(), specifically:\n" +"\n" +" 0 - relative to the start of the file (SEEK_SET)\n" +" 1 - relative to the current buffer position (SEEK_CUR)\n" +" 2 - relative to the end of the file (SEEK_END)"); + +#define FCNTL_LOCKF_METHODDEF \ + {"lockf", (PyCFunction)fcntl_lockf, METH_VARARGS, fcntl_lockf__doc__}, + static PyObject * -fcntl_lockf(PyObject *self, PyObject *args) +fcntl_lockf_impl(PyModuleDef *module, int fd, int code, PyObject *lenobj, PyObject *startobj, int whence); + +static PyObject * +fcntl_lockf(PyModuleDef *module, PyObject *args) { - int fd, code, ret, whence = 0; - PyObject *lenobj = NULL, *startobj = NULL; + PyObject *return_value = NULL; + int fd; + int code; + PyObject *lenobj = NULL; + PyObject *startobj = NULL; + int whence = 0; - if (!PyArg_ParseTuple(args, "O&i|OOi:lockf", - conv_descriptor, &fd, &code, - &lenobj, &startobj, &whence)) - return NULL; + if (!PyArg_ParseTuple(args, + "O&i|OOi:lockf", + conv_descriptor, &fd, &code, &lenobj, &startobj, &whence)) + goto exit; + return_value = fcntl_lockf_impl(module, fd, code, lenobj, startobj, whence); + +exit: + return return_value; +} + +static PyObject * +fcntl_lockf_impl(PyModuleDef *module, int fd, int code, PyObject *lenobj, PyObject *startobj, int whence) +/*[clinic end generated code: checksum=26d08a7fe50990b7443a197ddcc106bcb6f10bf1]*/ +{ + int ret; #ifndef LOCK_SH #define LOCK_SH 1 /* shared lock */ @@ -374,43 +539,18 @@ PyErr_SetFromErrno(PyExc_IOError); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyDoc_STRVAR(lockf_doc, -"lockf (fd, operation, length=0, start=0, whence=0)\n\ -\n\ -This is essentially a wrapper around the fcntl() locking calls. fd is the\n\ -file descriptor of the file to lock or unlock, and operation is one of the\n\ -following values:\n\ -\n\ - LOCK_UN - unlock\n\ - LOCK_SH - acquire a shared lock\n\ - LOCK_EX - acquire an exclusive lock\n\ -\n\ -When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n\ -LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the\n\ -lock cannot be acquired, an IOError will be raised and the exception will\n\ -have an errno attribute set to EACCES or EAGAIN (depending on the operating\n\ -system -- for portability, check for either value).\n\ -\n\ -length is the number of bytes to lock, with the default meaning to lock to\n\ -EOF. start is the byte offset, relative to whence, to that the lock\n\ -starts. whence is as with fileobj.seek(), specifically:\n\ -\n\ - 0 - relative to the start of the file (SEEK_SET)\n\ - 1 - relative to the current buffer position (SEEK_CUR)\n\ - 2 - relative to the end of the file (SEEK_END)"); /* List of functions */ static PyMethodDef fcntl_methods[] = { - {"fcntl", fcntl_fcntl, METH_VARARGS, fcntl_doc}, + FCNTL_FCNTL_METHODDEF {"ioctl", fcntl_ioctl, METH_VARARGS, ioctl_doc}, - {"flock", fcntl_flock, METH_VARARGS, flock_doc}, - {"lockf", fcntl_lockf, METH_VARARGS, lockf_doc}, - {NULL, NULL} /* sentinel */ + FCNTL_FLOCK_METHODDEF + FCNTL_LOCKF_METHODDEF + {NULL, NULL} /* sentinel */ };