@@ -54,57 +54,68 @@ static PyObject *
54
54
fcntl_fcntl_impl (PyObject * module , int fd , int code , PyObject * arg )
55
55
/*[clinic end generated code: output=888fc93b51c295bd input=7955340198e5f334]*/
56
56
{
57
- unsigned int int_arg = 0 ;
58
57
int ret ;
59
- char * str ;
60
- Py_ssize_t len ;
61
- char buf [1024 ];
62
58
int async_err = 0 ;
63
59
64
60
if (PySys_Audit ("fcntl.fcntl" , "iiO" , fd , code , arg ? arg : Py_None ) < 0 ) {
65
61
return NULL ;
66
62
}
67
63
68
- if (arg != NULL ) {
69
- int parse_result ;
70
-
71
- if (PyArg_Parse (arg , "s#" , & str , & len )) {
72
- if ((size_t )len > sizeof buf ) {
73
- PyErr_SetString (PyExc_ValueError ,
74
- "fcntl string arg too long" );
64
+ if (arg == NULL || PyIndex_Check (arg )) {
65
+ unsigned int int_arg = 0 ;
66
+ if (arg != NULL ) {
67
+ if (!PyArg_Parse (arg , "I" , & int_arg )) {
75
68
return NULL ;
76
69
}
77
- memcpy (buf , str , len );
78
- do {
79
- Py_BEGIN_ALLOW_THREADS
80
- ret = fcntl (fd , code , buf );
81
- Py_END_ALLOW_THREADS
82
- } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
83
- if (ret < 0 ) {
84
- return !async_err ? PyErr_SetFromErrno (PyExc_OSError ) : NULL ;
85
- }
86
- return PyBytes_FromStringAndSize (buf , len );
87
70
}
88
71
89
- PyErr_Clear ();
90
- parse_result = PyArg_Parse ( arg ,
91
- "I;fcntl requires a file or file descriptor,"
92
- " an integer and optionally a third integer or a string" ,
93
- & int_arg );
94
- if (! parse_result ) {
95
- return NULL ;
72
+ do {
73
+ Py_BEGIN_ALLOW_THREADS
74
+ ret = fcntl ( fd , code , ( int ) int_arg );
75
+ Py_END_ALLOW_THREADS
76
+ } while ( ret == -1 && errno == EINTR && !( async_err = PyErr_CheckSignals ()) );
77
+ if (ret < 0 ) {
78
+ return ! async_err ? PyErr_SetFromErrno ( PyExc_OSError ) : NULL ;
96
79
}
80
+ return PyLong_FromLong (ret );
97
81
}
82
+ else if (PyUnicode_Check (arg ) || PyObject_CheckBuffer (arg )) {
83
+ #define FNCTL_BUFSZ 1024
84
+ Py_buffer view ;
85
+ char buf [FNCTL_BUFSZ + 1 ]; /* argument plus NUL byte */
98
86
99
- do {
100
- Py_BEGIN_ALLOW_THREADS
101
- ret = fcntl (fd , code , (int )int_arg );
102
- Py_END_ALLOW_THREADS
103
- } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
104
- if (ret < 0 ) {
105
- return !async_err ? PyErr_SetFromErrno (PyExc_OSError ) : NULL ;
87
+ if (!PyArg_Parse (arg , "s*" , & view )) {
88
+ return NULL ;
89
+ }
90
+ Py_ssize_t len = view .len ;
91
+ if (len > FNCTL_BUFSZ ) {
92
+ PyErr_SetString (PyExc_ValueError ,
93
+ "fcntl argument 3 is too long" );
94
+ PyBuffer_Release (& view );
95
+ return NULL ;
96
+ }
97
+ memcpy (buf , view .buf , len );
98
+ buf [len ] = '\0' ;
99
+ PyBuffer_Release (& view );
100
+
101
+ do {
102
+ Py_BEGIN_ALLOW_THREADS
103
+ ret = fcntl (fd , code , buf );
104
+ Py_END_ALLOW_THREADS
105
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
106
+ if (ret < 0 ) {
107
+ return !async_err ? PyErr_SetFromErrno (PyExc_OSError ) : NULL ;
108
+ }
109
+ return PyBytes_FromStringAndSize (buf , len );
110
+ #undef FNCTL_BUFSZ
111
+ }
112
+ else {
113
+ PyErr_Format (PyExc_TypeError ,
114
+ "fcntl(): argument 3 must be an integer, "
115
+ "a bytes-like object, or a string, not %T" ,
116
+ arg );
117
+ return NULL ;
106
118
}
107
- return PyLong_FromLong ((long )ret );
108
119
}
109
120
110
121
@@ -113,7 +124,7 @@ fcntl.ioctl
113
124
114
125
fd: fildes
115
126
request as code: unsigned_long(bitwise=True)
116
- arg as ob_arg : object(c_default='NULL') = 0
127
+ arg: object(c_default='NULL') = 0
117
128
mutate_flag as mutate_arg: bool = True
118
129
/
119
130
@@ -148,11 +159,10 @@ code.
148
159
[clinic start generated code]*/
149
160
150
161
static PyObject *
151
- fcntl_ioctl_impl (PyObject * module , int fd , unsigned long code ,
152
- PyObject * ob_arg , int mutate_arg )
153
- /*[clinic end generated code: output=3d8eb6828666cea1 input=cee70f6a27311e58 ]*/
162
+ fcntl_ioctl_impl (PyObject * module , int fd , unsigned long code , PyObject * arg ,
163
+ int mutate_arg )
164
+ /*[clinic end generated code: output=f72baba2454d7a62 input=9c6cca5e2c339622 ]*/
154
165
{
155
- #define IOCTL_BUFSZ 1024
156
166
/* We use the unsigned non-checked 'I' format for the 'code' parameter
157
167
because the system expects it to be a 32bit bit field value
158
168
regardless of it being passed as an int or unsigned long on
@@ -163,114 +173,102 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code,
163
173
in their unsigned long ioctl codes this will break and need
164
174
special casing based on the platform being built on.
165
175
*/
166
- int arg = 0 ;
167
176
int ret ;
168
- Py_buffer pstr ;
169
- char * str ;
170
- Py_ssize_t len ;
171
- char buf [IOCTL_BUFSZ + 1 ]; /* argument plus NUL byte */
177
+ int async_err = 0 ;
172
178
173
- if (PySys_Audit ("fcntl.ioctl" , "ikO" , fd , code ,
174
- ob_arg ? ob_arg : Py_None ) < 0 ) {
179
+ if (PySys_Audit ("fcntl.ioctl" , "ikO" , fd , code , arg ? arg : Py_None ) < 0 ) {
175
180
return NULL ;
176
181
}
177
182
178
- if (ob_arg != NULL ) {
179
- if (PyArg_Parse (ob_arg , "w*:ioctl" , & pstr )) {
180
- char * arg ;
181
- str = pstr .buf ;
182
- len = pstr .len ;
183
-
184
- if (mutate_arg ) {
185
- if (len <= IOCTL_BUFSZ ) {
186
- memcpy (buf , str , len );
187
- buf [len ] = '\0' ;
188
- arg = buf ;
183
+ if (arg == NULL || PyIndex_Check (arg )) {
184
+ int int_arg = 0 ;
185
+ if (arg != NULL ) {
186
+ if (!PyArg_Parse (arg , "i" , & int_arg )) {
187
+ return NULL ;
188
+ }
189
+ }
190
+
191
+ do {
192
+ Py_BEGIN_ALLOW_THREADS
193
+ ret = ioctl (fd , code , int_arg );
194
+ Py_END_ALLOW_THREADS
195
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
196
+ if (ret < 0 ) {
197
+ return !async_err ? PyErr_SetFromErrno (PyExc_OSError ) : NULL ;
198
+ }
199
+ return PyLong_FromLong (ret );
200
+ }
201
+ else if (PyUnicode_Check (arg ) || PyObject_CheckBuffer (arg )) {
202
+ Py_buffer view ;
203
+ #define IOCTL_BUFSZ 1024
204
+ char buf [IOCTL_BUFSZ + 1 ]; /* argument plus NUL byte */
205
+ if (mutate_arg && !PyBytes_Check (arg ) && !PyUnicode_Check (arg )) {
206
+ if (PyObject_GetBuffer (arg , & view , PyBUF_WRITABLE ) == 0 ) {
207
+ if (view .len <= IOCTL_BUFSZ ) {
208
+ memcpy (buf , view .buf , view .len );
209
+ buf [view .len ] = '\0' ;
210
+ do {
211
+ Py_BEGIN_ALLOW_THREADS
212
+ ret = ioctl (fd , code , buf );
213
+ Py_END_ALLOW_THREADS
214
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
215
+ memcpy (view .buf , buf , view .len );
189
216
}
190
217
else {
191
- arg = str ;
218
+ do {
219
+ Py_BEGIN_ALLOW_THREADS
220
+ ret = ioctl (fd , code , view .buf );
221
+ Py_END_ALLOW_THREADS
222
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
192
223
}
193
- }
194
- else {
195
- if (len > IOCTL_BUFSZ ) {
196
- PyBuffer_Release (& pstr );
197
- PyErr_SetString (PyExc_ValueError ,
198
- "ioctl string arg too long" );
224
+ if (ret < 0 ) {
225
+ if (!async_err ) {
226
+ PyErr_SetFromErrno (PyExc_OSError );
227
+ }
228
+ PyBuffer_Release (& view );
199
229
return NULL ;
200
230
}
201
- else {
202
- memcpy (buf , str , len );
203
- buf [len ] = '\0' ;
204
- arg = buf ;
205
- }
206
- }
207
- if (buf == arg ) {
208
- Py_BEGIN_ALLOW_THREADS /* think array.resize() */
209
- ret = ioctl (fd , code , arg );
210
- Py_END_ALLOW_THREADS
211
- }
212
- else {
213
- ret = ioctl (fd , code , arg );
214
- }
215
- if (mutate_arg && (len <= IOCTL_BUFSZ )) {
216
- memcpy (str , buf , len );
217
- }
218
- if (ret < 0 ) {
219
- PyErr_SetFromErrno (PyExc_OSError );
220
- PyBuffer_Release (& pstr );
221
- return NULL ;
222
- }
223
- PyBuffer_Release (& pstr );
224
- if (mutate_arg ) {
231
+ PyBuffer_Release (& view );
225
232
return PyLong_FromLong (ret );
226
233
}
227
- else {
228
- return PyBytes_FromStringAndSize ( buf , len ) ;
234
+ if (! PyErr_ExceptionMatches ( PyExc_BufferError )) {
235
+ return NULL ;
229
236
}
237
+ PyErr_Clear ();
230
238
}
231
239
232
- PyErr_Clear ();
233
- if (PyArg_Parse (ob_arg , "s*:ioctl" , & pstr )) {
234
- str = pstr .buf ;
235
- len = pstr .len ;
236
- if (len > IOCTL_BUFSZ ) {
237
- PyBuffer_Release (& pstr );
238
- PyErr_SetString (PyExc_ValueError ,
239
- "ioctl string arg too long" );
240
- return NULL ;
241
- }
242
- memcpy (buf , str , len );
243
- buf [len ] = '\0' ;
240
+ if (!PyArg_Parse (arg , "s*" , & view )) {
241
+ return NULL ;
242
+ }
243
+ Py_ssize_t len = view .len ;
244
+ if (len > IOCTL_BUFSZ ) {
245
+ PyErr_SetString (PyExc_ValueError ,
246
+ "ioctl argument 3 is too long" );
247
+ PyBuffer_Release (& view );
248
+ return NULL ;
249
+ }
250
+ memcpy (buf , view .buf , len );
251
+ buf [len ] = '\0' ;
252
+ PyBuffer_Release (& view );
253
+
254
+ do {
244
255
Py_BEGIN_ALLOW_THREADS
245
256
ret = ioctl (fd , code , buf );
246
257
Py_END_ALLOW_THREADS
247
- if (ret < 0 ) {
248
- PyErr_SetFromErrno (PyExc_OSError );
249
- PyBuffer_Release (& pstr );
250
- return NULL ;
251
- }
252
- PyBuffer_Release (& pstr );
253
- return PyBytes_FromStringAndSize (buf , len );
254
- }
255
-
256
- PyErr_Clear ();
257
- if (!PyArg_Parse (ob_arg ,
258
- "i;ioctl requires a file or file descriptor,"
259
- " an integer and optionally an integer or buffer argument" ,
260
- & arg )) {
261
- return NULL ;
258
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
259
+ if (ret < 0 ) {
260
+ return !async_err ? PyErr_SetFromErrno (PyExc_OSError ) : NULL ;
262
261
}
263
- // Fall-through to outside the 'if' statement.
262
+ return PyBytes_FromStringAndSize (buf , len );
263
+ #undef IOCTL_BUFSZ
264
264
}
265
- Py_BEGIN_ALLOW_THREADS
266
- ret = ioctl ( fd , code , arg );
267
- Py_END_ALLOW_THREADS
268
- if ( ret < 0 ) {
269
- PyErr_SetFromErrno ( PyExc_OSError );
265
+ else {
266
+ PyErr_Format ( PyExc_TypeError ,
267
+ "ioctl(): argument 3 must be an integer, "
268
+ "a bytes-like object, or a string, not %T" ,
269
+ arg );
270
270
return NULL ;
271
271
}
272
- return PyLong_FromLong ((long )ret );
273
- #undef IOCTL_BUFSZ
274
272
}
275
273
276
274
/*[clinic input]
0 commit comments