diff options
author | Michael W. Hudson <mwh@python.net> | 2003-03-03 12:29:42 (GMT) |
---|---|---|
committer | Michael W. Hudson <mwh@python.net> | 2003-03-03 12:29:42 (GMT) |
commit | f00899866888408106fea4147a9d2cdc2f1e8dbc (patch) | |
tree | 32aae5a6d01192bc79456886bd8d299ad84ecdeb /Modules | |
parent | 122152451e1bc7aaff69d28b8950afa7848c6de6 (diff) | |
download | cpython-f00899866888408106fea4147a9d2cdc2f1e8dbc.zip cpython-f00899866888408106fea4147a9d2cdc2f1e8dbc.tar.gz cpython-f00899866888408106fea4147a9d2cdc2f1e8dbc.tar.bz2 |
Fix bug
[ 555817 ] Flawed fcntl.ioctl implementation.
with my patch that allows for an array to be mutated when passed
as the buffer argument to ioctl() (details complicated by
backwards compatibility considerations -- read the docs!).
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/fcntlmodule.c | 94 |
1 files changed, 83 insertions, 11 deletions
diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c index c5d9b4d..c495a77 100644 --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -99,8 +99,62 @@ fcntl_ioctl(PyObject *self, PyObject *args) int ret; char *str; int len; + int mutate_arg = 0; char buf[1024]; + if (PyArg_ParseTuple(args, "O&iw#|i:ioctl", + conv_descriptor, &fd, &code, + &str, &len, &mutate_arg)) { + char *arg; + + if (PyTuple_Size(args) == 3) { + /* warning goes here in 2.4 */ + mutate_arg = 0; + } + if (mutate_arg) { + if (len <= sizeof buf) { + memcpy(buf, str, len); + arg = buf; + } + else { + arg = str; + } + } + else { + if (len > sizeof buf) { + PyErr_SetString(PyExc_ValueError, + "ioctl string arg too long"); + return NULL; + } + else { + memcpy(buf, str, len); + 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 < sizeof buf)) { + memcpy(str, buf, len); + } + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + if (mutate_arg) { + return PyInt_FromLong(ret); + } + else { + return PyString_FromStringAndSize(buf, len); + } + } + + PyErr_Clear(); if (PyArg_ParseTuple(args, "O&is#:ioctl", conv_descriptor, &fd, &code, &str, &len)) { if (len > sizeof buf) { @@ -123,7 +177,7 @@ fcntl_ioctl(PyObject *self, PyObject *args) arg = 0; if (!PyArg_ParseTuple(args, "O&i|i;ioctl requires a file or file descriptor," - " an integer and optionally a third integer or a string", + " an integer and optionally a integer or buffer argument", conv_descriptor, &fd, &code, &arg)) { return NULL; } @@ -138,17 +192,35 @@ fcntl_ioctl(PyObject *self, PyObject *args) } PyDoc_STRVAR(ioctl_doc, -"ioctl(fd, opt, [arg])\n\ +"ioctl(fd, opt[, arg[, mutate_flag]])\n\ \n\ -Perform the requested operation on file descriptor fd. The operation\n\ -is defined by op and is operating system dependent. Typically these\n\ -codes can be retrieved from the library module IOCTL. The argument arg\n\ -is optional, and defaults to 0; it may be an int or a string. If arg is\n\ -given as a string, the return value of ioctl is a string of that length,\n\ -containing the resulting value put in the arg buffer by the operating system.\n\ -The length of the arg string is not allowed to exceed 1024 bytes. If the arg\n\ -given is an integer or if none is specified, the result value is an integer\n\ -corresponding to the return value of the ioctl call in the C code."); +Perform the requested operation on file descriptor fd. The operation is\n\ +defined by op and is operating system dependent. Typically these codes are\n\ +retrieved from the fcntl or termios library modules.\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."); /* flock(fd, operation) */ |