Issue 20152, 22821: Port the fcntl module to Argument Clinic.
Along the way, fix an argumrnt to fcntl.fcntl to be an int instead of a long. Thanks to Serhiy Storchaka for reviewing my Clinic patch and for writing the patch to fix the long/int issue.
This commit is contained in:
parent
df1b699447
commit
b7299ddbc7
|
@ -0,0 +1,188 @@
|
|||
/*[clinic input]
|
||||
preserve
|
||||
[clinic start generated code]*/
|
||||
|
||||
PyDoc_STRVAR(fcntl_fcntl__doc__,
|
||||
"fcntl($module, fd, code, arg=None, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Perform the operation `code` on file descriptor fd.\n"
|
||||
"\n"
|
||||
"The values used for `code` 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_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;
|
||||
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;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(fcntl_ioctl__doc__,
|
||||
"ioctl($module, fd, op, arg=None, mutate_flag=True, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Perform the operation op on file descriptor fd.\n"
|
||||
"\n"
|
||||
"The values used for op are operating system dependent, and are available as\n"
|
||||
"constants in the fcntl or termios library modules, using the same names as\n"
|
||||
"used in the relevant C header files.\n"
|
||||
"\n"
|
||||
"The argument `arg` is optional, and defaults to 0; it may be an int or a\n"
|
||||
"buffer containing character data (most likely a string or an array).\n"
|
||||
"\n"
|
||||
"If the argument is a mutable buffer (such as an array) and if the\n"
|
||||
"mutate_flag argument (which is only allowed in this case) is true then the\n"
|
||||
"buffer is (in effect) passed to the operating system and changes made by\n"
|
||||
"the OS will be reflected in the contents of the buffer after the call has\n"
|
||||
"returned. The return value is the integer returned by the ioctl system\n"
|
||||
"call.\n"
|
||||
"\n"
|
||||
"If the argument is a mutable buffer and the mutable_flag argument is not\n"
|
||||
"passed or is false, the behavior is as if a string had been passed. This\n"
|
||||
"behavior will change in future releases of Python.\n"
|
||||
"\n"
|
||||
"If the argument is an immutable buffer (most likely a string) then a copy\n"
|
||||
"of the buffer is passed to the operating system and the return value is a\n"
|
||||
"string of the same length containing whatever the operating system put in\n"
|
||||
"the buffer. The length of the arg buffer in this case is not allowed to\n"
|
||||
"exceed 1024 bytes.\n"
|
||||
"\n"
|
||||
"If the arg given is an integer or if none is specified, the result value is\n"
|
||||
"an integer corresponding to the return value of the ioctl call in the C\n"
|
||||
"code.");
|
||||
|
||||
#define FCNTL_IOCTL_METHODDEF \
|
||||
{"ioctl", (PyCFunction)fcntl_ioctl, METH_VARARGS, fcntl_ioctl__doc__},
|
||||
|
||||
static PyObject *
|
||||
fcntl_ioctl_impl(PyModuleDef *module, int fd, unsigned int code, PyObject *ob_arg, int mutate_arg);
|
||||
|
||||
static PyObject *
|
||||
fcntl_ioctl(PyModuleDef *module, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int fd;
|
||||
unsigned int code;
|
||||
PyObject *ob_arg = NULL;
|
||||
int mutate_arg = 1;
|
||||
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"O&I|Op:ioctl",
|
||||
conv_descriptor, &fd, &code, &ob_arg, &mutate_arg))
|
||||
goto exit;
|
||||
return_value = fcntl_ioctl_impl(module, fd, code, ob_arg, mutate_arg);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(fcntl_flock__doc__,
|
||||
"flock($module, fd, code, /)\n"
|
||||
"--\n"
|
||||
"\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_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;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(fcntl_lockf__doc__,
|
||||
"lockf($module, fd, code, lenobj=None, startobj=None, whence=0, /)\n"
|
||||
"--\n"
|
||||
"\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_impl(PyModuleDef *module, int fd, int code, PyObject *lenobj, PyObject *startobj, int whence);
|
||||
|
||||
static PyObject *
|
||||
fcntl_lockf(PyModuleDef *module, PyObject *args)
|
||||
{
|
||||
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))
|
||||
goto exit;
|
||||
return_value = fcntl_lockf_impl(module, fd, code, lenobj, startobj, whence);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=84bdde73a92f7c61 input=a9049054013a1b77]*/
|
|
@ -15,6 +15,12 @@
|
|||
#include <stropts.h>
|
||||
#endif
|
||||
|
||||
/*[clinic input]
|
||||
output preset file
|
||||
module fcntl
|
||||
[clinic start generated code]*/
|
||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c7356fdb126a904a]*/
|
||||
|
||||
static int
|
||||
conv_descriptor(PyObject *object, int *target)
|
||||
{
|
||||
|
@ -26,48 +32,72 @@ conv_descriptor(PyObject *object, int *target)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Must come after conv_descriptor definition. */
|
||||
#include "clinic/fcntlmodule.c.h"
|
||||
|
||||
/* fcntl(fd, op, [arg]) */
|
||||
/*[clinic input]
|
||||
fcntl.fcntl
|
||||
|
||||
fd: object(type='int', converter='conv_descriptor')
|
||||
code: int
|
||||
arg: object = NULL
|
||||
/
|
||||
|
||||
Perform the operation `code` on file descriptor fd.
|
||||
|
||||
The values used for `code` 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]*/
|
||||
|
||||
static PyObject *
|
||||
fcntl_fcntl(PyObject *self, PyObject *args)
|
||||
fcntl_fcntl_impl(PyModuleDef *module, int fd, int code, PyObject *arg)
|
||||
/*[clinic end generated code: output=afc5bfa74a03ef0d input=4850c13a41e86930]*/
|
||||
{
|
||||
int fd;
|
||||
int code;
|
||||
long arg;
|
||||
int int_arg = 0;
|
||||
int ret;
|
||||
char *str;
|
||||
Py_ssize_t len;
|
||||
char buf[1024];
|
||||
|
||||
if (PyArg_ParseTuple(args, "O&is#:fcntl",
|
||||
conv_descriptor, &fd, &code, &str, &len)) {
|
||||
if ((size_t)len > sizeof buf) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"fcntl string arg too long");
|
||||
return NULL;
|
||||
if (arg != NULL) {
|
||||
int parse_result;
|
||||
|
||||
if (PyArg_Parse(arg, "s#", &str, &len)) {
|
||||
if ((size_t)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;
|
||||
|
||||
PyErr_Clear();
|
||||
parse_result = PyArg_Parse(arg,
|
||||
"l;fcntl requires a file or file descriptor,"
|
||||
" an integer and optionally a third integer or a string",
|
||||
&int_arg);
|
||||
if (!parse_result) {
|
||||
return NULL;
|
||||
}
|
||||
return PyBytes_FromStringAndSize(buf, len);
|
||||
}
|
||||
|
||||
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, int_arg);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (ret < 0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
|
@ -76,29 +106,53 @@ fcntl_fcntl(PyObject *self, PyObject *args)
|
|||
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.");
|
||||
|
||||
/*[clinic input]
|
||||
fcntl.ioctl
|
||||
|
||||
/* ioctl(fd, op, [arg]) */
|
||||
fd: object(type='int', converter='conv_descriptor')
|
||||
op as code: unsigned_int(bitwise=True)
|
||||
arg as ob_arg: object = NULL
|
||||
mutate_flag as mutate_arg: bool = True
|
||||
/
|
||||
|
||||
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 or termios library modules, 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
|
||||
buffer containing character data (most likely a string or an array).
|
||||
|
||||
If the argument is a mutable buffer (such as an array) and if the
|
||||
mutate_flag argument (which is only allowed in this case) is true then the
|
||||
buffer is (in effect) passed to the operating system and changes made by
|
||||
the OS will be reflected in the contents of the buffer after the call has
|
||||
returned. The return value is the integer returned by the ioctl system
|
||||
call.
|
||||
|
||||
If the argument is a mutable buffer and the mutable_flag argument is not
|
||||
passed or is false, the behavior is as if a string had been passed. This
|
||||
behavior will change in future releases of Python.
|
||||
|
||||
If the argument is an immutable buffer (most likely a string) then a copy
|
||||
of the buffer is passed to the operating system and the return value is a
|
||||
string of the same length containing whatever the operating system put in
|
||||
the buffer. The length of the arg buffer in this case 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 ioctl call in the C
|
||||
code.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
fcntl_ioctl(PyObject *self, PyObject *args)
|
||||
fcntl_ioctl_impl(PyModuleDef *module, int fd, unsigned int code, PyObject *ob_arg, int mutate_arg)
|
||||
/*[clinic end generated code: output=ad47738c118622bf input=a55a6ee8e494c449]*/
|
||||
{
|
||||
#define IOCTL_BUFSZ 1024
|
||||
int fd;
|
||||
/* In PyArg_ParseTuple below, we use the unsigned non-checked 'I'
|
||||
/* We use the unsigned non-checked 'I'
|
||||
format for the 'code' parameter because Python turns 0x8000000
|
||||
into either a large positive number (PyLong or PyInt on 64-bit
|
||||
platforms) or a negative number on others (32-bit PyInt)
|
||||
|
@ -111,101 +165,98 @@ fcntl_ioctl(PyObject *self, PyObject *args)
|
|||
in their unsigned long ioctl codes this will break and need
|
||||
special casing based on the platform being built on.
|
||||
*/
|
||||
unsigned int code;
|
||||
int arg;
|
||||
int arg = 0;
|
||||
int ret;
|
||||
Py_buffer pstr;
|
||||
char *str;
|
||||
Py_ssize_t len;
|
||||
int mutate_arg = 1;
|
||||
char buf[IOCTL_BUFSZ+1]; /* argument plus NUL byte */
|
||||
|
||||
if (PyArg_ParseTuple(args, "O&Iw*|i:ioctl",
|
||||
conv_descriptor, &fd, &code,
|
||||
&pstr, &mutate_arg)) {
|
||||
char *arg;
|
||||
str = pstr.buf;
|
||||
len = pstr.len;
|
||||
if (ob_arg != NULL) {
|
||||
if (PyArg_Parse(ob_arg, "w*:ioctl", &pstr)) {
|
||||
char *arg;
|
||||
str = pstr.buf;
|
||||
len = pstr.len;
|
||||
|
||||
if (mutate_arg) {
|
||||
if (len <= IOCTL_BUFSZ) {
|
||||
memcpy(buf, str, len);
|
||||
buf[len] = '\0';
|
||||
arg = buf;
|
||||
if (mutate_arg) {
|
||||
if (len <= IOCTL_BUFSZ) {
|
||||
memcpy(buf, str, len);
|
||||
buf[len] = '\0';
|
||||
arg = buf;
|
||||
}
|
||||
else {
|
||||
arg = str;
|
||||
}
|
||||
}
|
||||
else {
|
||||
arg = str;
|
||||
if (len > IOCTL_BUFSZ) {
|
||||
PyBuffer_Release(&pstr);
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"ioctl string arg too long");
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
memcpy(buf, str, len);
|
||||
buf[len] = '\0';
|
||||
arg = buf;
|
||||
}
|
||||
}
|
||||
if (buf == arg) {
|
||||
Py_BEGIN_ALLOW_THREADS /* think array.resize() */
|
||||
ret = ioctl(fd, code, arg);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
else {
|
||||
ret = ioctl(fd, code, arg);
|
||||
}
|
||||
if (mutate_arg && (len <= IOCTL_BUFSZ)) {
|
||||
memcpy(str, buf, len);
|
||||
}
|
||||
PyBuffer_Release(&pstr); /* No further access to str below this point */
|
||||
if (ret < 0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
if (mutate_arg) {
|
||||
return PyLong_FromLong(ret);
|
||||
}
|
||||
else {
|
||||
return PyBytes_FromStringAndSize(buf, len);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
PyErr_Clear();
|
||||
if (PyArg_Parse(ob_arg, "s*:ioctl", &pstr)) {
|
||||
str = pstr.buf;
|
||||
len = pstr.len;
|
||||
if (len > IOCTL_BUFSZ) {
|
||||
PyBuffer_Release(&pstr);
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"ioctl string arg too long");
|
||||
"ioctl string arg too long");
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
memcpy(buf, str, len);
|
||||
buf[len] = '\0';
|
||||
arg = buf;
|
||||
}
|
||||
}
|
||||
if (buf == arg) {
|
||||
Py_BEGIN_ALLOW_THREADS /* think array.resize() */
|
||||
ret = ioctl(fd, code, arg);
|
||||
memcpy(buf, str, len);
|
||||
buf[len] = '\0';
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = ioctl(fd, code, buf);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
else {
|
||||
ret = ioctl(fd, code, arg);
|
||||
}
|
||||
if (mutate_arg && (len <= IOCTL_BUFSZ)) {
|
||||
memcpy(str, buf, len);
|
||||
}
|
||||
PyBuffer_Release(&pstr); /* No further access to str below this point */
|
||||
if (ret < 0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
if (mutate_arg) {
|
||||
return PyLong_FromLong(ret);
|
||||
}
|
||||
else {
|
||||
if (ret < 0) {
|
||||
PyBuffer_Release(&pstr);
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
PyBuffer_Release(&pstr);
|
||||
return PyBytes_FromStringAndSize(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
if (PyArg_ParseTuple(args, "O&Is*:ioctl",
|
||||
conv_descriptor, &fd, &code, &pstr)) {
|
||||
str = pstr.buf;
|
||||
len = pstr.len;
|
||||
if (len > IOCTL_BUFSZ) {
|
||||
PyBuffer_Release(&pstr);
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"ioctl string arg too long");
|
||||
return NULL;
|
||||
PyErr_Clear();
|
||||
if (!PyArg_Parse(ob_arg,
|
||||
"i;ioctl requires a file or file descriptor,"
|
||||
" an integer and optionally an integer or buffer argument",
|
||||
&arg)) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(buf, str, len);
|
||||
buf[len] = '\0';
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = ioctl(fd, code, buf);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (ret < 0) {
|
||||
PyBuffer_Release(&pstr);
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
PyBuffer_Release(&pstr);
|
||||
return PyBytes_FromStringAndSize(buf, len);
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
arg = 0;
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"O&I|i;ioctl requires a file or file descriptor,"
|
||||
" an integer and optionally an integer or buffer argument",
|
||||
conv_descriptor, &fd, &code, &arg)) {
|
||||
return NULL;
|
||||
// Fall-through to outside the 'if' statement.
|
||||
}
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = ioctl(fd, code, arg);
|
||||
|
@ -218,52 +269,25 @@ fcntl_ioctl(PyObject *self, PyObject *args)
|
|||
#undef IOCTL_BUFSZ
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(ioctl_doc,
|
||||
"ioctl(fd, op[, arg[, mutate_flag]])\n\
|
||||
\n\
|
||||
Perform the operation op on file descriptor fd. The values used for op\n\
|
||||
are operating system dependent, and are available as constants in the\n\
|
||||
fcntl or termios library modules, using the same names as used in the\n\
|
||||
relevant C header files.\n\
|
||||
\n\
|
||||
The argument arg is optional, and defaults to 0; it may be an int or a\n\
|
||||
buffer containing character data (most likely a string or an array). \n\
|
||||
\n\
|
||||
If the argument is a mutable buffer (such as an array) and if the\n\
|
||||
mutate_flag argument (which is only allowed in this case) is true then the\n\
|
||||
buffer is (in effect) passed to the operating system and changes made by\n\
|
||||
the OS will be reflected in the contents of the buffer after the call has\n\
|
||||
returned. The return value is the integer returned by the ioctl system\n\
|
||||
call.\n\
|
||||
\n\
|
||||
If the argument is a mutable buffer and the mutable_flag argument is not\n\
|
||||
passed or is false, the behavior is as if a string had been passed. This\n\
|
||||
behavior will change in future releases of Python.\n\
|
||||
\n\
|
||||
If the argument is an immutable buffer (most likely a string) then a copy\n\
|
||||
of the buffer is passed to the operating system and the return value is a\n\
|
||||
string of the same length containing whatever the operating system put in\n\
|
||||
the buffer. The length of the arg buffer in this case is not allowed to\n\
|
||||
exceed 1024 bytes.\n\
|
||||
\n\
|
||||
If the arg given is an integer or if none is specified, the result value is\n\
|
||||
an integer corresponding to the return value of the ioctl call in the C\n\
|
||||
code.");
|
||||
/*[clinic input]
|
||||
fcntl.flock
|
||||
|
||||
fd: object(type='int', converter='conv_descriptor')
|
||||
code: int
|
||||
/
|
||||
|
||||
/* flock(fd, operation) */
|
||||
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]*/
|
||||
|
||||
static PyObject *
|
||||
fcntl_flock(PyObject *self, PyObject *args)
|
||||
fcntl_flock_impl(PyModuleDef *module, int fd, int code)
|
||||
/*[clinic end generated code: output=c9035133a7dbfc96 input=b762aa9448d05e43]*/
|
||||
{
|
||||
int fd;
|
||||
int code;
|
||||
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 +323,49 @@ fcntl_flock(PyObject *self, PyObject *args)
|
|||
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
|
||||
|
||||
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]*/
|
||||
|
||||
/* lockf(fd, operation) */
|
||||
static PyObject *
|
||||
fcntl_lockf(PyObject *self, PyObject *args)
|
||||
fcntl_lockf_impl(PyModuleDef *module, int fd, int code, PyObject *lenobj, PyObject *startobj, int whence)
|
||||
/*[clinic end generated code: output=5536df2892bf3ce9 input=44856fa06db36184]*/
|
||||
{
|
||||
int fd, code, ret, whence = 0;
|
||||
PyObject *lenobj = NULL, *startobj = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O&i|OOi:lockf",
|
||||
conv_descriptor, &fd, &code,
|
||||
&lenobj, &startobj, &whence))
|
||||
return NULL;
|
||||
int ret;
|
||||
|
||||
#ifndef LOCK_SH
|
||||
#define LOCK_SH 1 /* shared lock */
|
||||
|
@ -374,43 +418,17 @@ fcntl_lockf(PyObject *self, PyObject *args)
|
|||
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},
|
||||
{"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_FCNTL_METHODDEF
|
||||
FCNTL_IOCTL_METHODDEF
|
||||
FCNTL_FLOCK_METHODDEF
|
||||
FCNTL_LOCKF_METHODDEF
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue