Skip to content

Commit ed72a9b

Browse files
committed
changes from remarks.
- removing custom code out of `fcntl.fcntl`. - F_GETPATH requires MAXPATHLEN or greater so we increase the buffer size to be able to cater with F_KINFO greater size. - `fcntl.kinfoalloc` preallocate a proper kinfo_file buffer. - `fcntl.kinfodict` returns a handy representation of the data.
1 parent e765b29 commit ed72a9b

File tree

6 files changed

+141
-26
lines changed

6 files changed

+141
-26
lines changed

Doc/whatsnew/3.13.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ email
212212
(Contributed by Thomas Dwyer and Victor Stinner for :gh:`102988` to improve
213213
the CVE-2023-27043 fix.)
214214

215+
fcntl
216+
-----
217+
218+
* Added constant :data:`fcntl.F_KINFO`
219+
215220
fractions
216221
---------
217222

Lib/test/test_fcntl.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,11 @@ def test_fcntl_f_getpath(self):
196196
@unittest.skipUnless(sys.platform.startswith("freebsd") and hasattr(fcntl, "F_KINFO"), "F_KINFO is only available on freebsd")
197197
def test_fcntl_f_kinfo(self):
198198
self.f = open(TESTFN, 'wb')
199+
buffer = fcntl.kinfoalloc()
199200
expected = os.path.abspath(TESTFN).encode('utf-8')
200-
res = fcntl.fcntl(self.f.fileno(), fcntl.F_KINFO)
201-
self.assertEqual(expected, res)
201+
res = fcntl.fcntl(self.f.fileno(), fcntl.F_KINFO, buffer)
202+
path = fcntl.kinfodict(res)["path"]
203+
self.assertEqual(expected, path)
202204

203205
@unittest.skipUnless(
204206
hasattr(fcntl, "F_SETPIPE_SZ") and hasattr(fcntl, "F_GETPIPE_SZ"),

Modules/clinic/fcntlmodule.c.h

Lines changed: 67 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/fcntlmodule.c

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
5959
int ret;
6060
char *str;
6161
Py_ssize_t len;
62-
char buf[1024];
6362
int async_err = 0;
6463

6564
if (PySys_Audit("fcntl.fcntl", "iiO", fd, code, arg ? arg : Py_None) < 0) {
@@ -68,14 +67,9 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
6867

6968
if (arg != NULL) {
7069
int parse_result;
71-
#ifdef F_KINFO
72-
if (code == F_KINFO) {
73-
PyErr_SetString(PyExc_ValueError,
74-
"fcntl arg not permitted with F_KINFO");
75-
}
76-
#endif
7770

7871
if (PyArg_Parse(arg, "s#", &str, &len)) {
72+
char buf[4096];
7973
if ((size_t)len > sizeof buf) {
8074
PyErr_SetString(PyExc_ValueError,
8175
"fcntl string arg too long");
@@ -103,21 +97,6 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
10397
}
10498
}
10599

106-
#ifdef F_KINFO
107-
if (code == F_KINFO) {
108-
struct kinfo_file f = {.kf_structsize = KINFO_FILE_SIZE};
109-
do {
110-
Py_BEGIN_ALLOW_THREADS
111-
ret = fcntl(fd, code, &f);
112-
Py_END_ALLOW_THREADS
113-
} while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
114-
if (ret < 0) {
115-
return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL;
116-
}
117-
return PyBytes_FromString(f.kf_path);
118-
}
119-
#endif
120-
121100
do {
122101
Py_BEGIN_ALLOW_THREADS
123102
ret = fcntl(fd, code, (int)int_arg);
@@ -463,13 +442,70 @@ fcntl_lockf_impl(PyObject *module, int fd, int code, PyObject *lenobj,
463442
Py_RETURN_NONE;
464443
}
465444

445+
#ifdef F_KINFO
446+
/*[clinic input]
447+
fcntl.kinfoalloc
448+
449+
Return a FreeBSD's kinfo_file buffer with the `kf_structsize` field pre-initialised.
450+
451+
[clinic start generated code]*/
452+
453+
static PyObject *
454+
fcntl_kinfoalloc_impl(PyObject *module)
455+
/*[clinic end generated code: output=c61603aeb3d91a0e input=28e2e82cc296f82c]*/
456+
{
457+
char buf[KINFO_FILE_SIZE+1];
458+
((struct kinfo_file *)buf)->kf_structsize = KINFO_FILE_SIZE;
459+
return PyBytes_FromStringAndSize(buf, KINFO_FILE_SIZE);
460+
}
461+
462+
/*[clinic input]
463+
fcntl.kinfodict
464+
465+
arg: object(c_default='NULL') = 0
466+
/
467+
468+
Return a FreeBSD's kinfo_file as dictionary.
469+
470+
[clinic start generated code]*/
471+
472+
static PyObject *
473+
fcntl_kinfodict_impl(PyObject *module, PyObject *arg)
474+
/*[clinic end generated code: output=3873ae40aeac8e7f input=faba1f2ce099752f]*/
475+
{
476+
PyObject *dict;
477+
478+
if (PySys_Audit("fcntl.kinfodict", "O", arg) < 0 || arg == NULL) {
479+
return NULL;
480+
}
481+
482+
dict = PyDict_New();
483+
if (dict) {
484+
struct kinfo_file *kf;
485+
kf = (struct kinfo_file *)PyBytes_AsString(arg);
486+
487+
PyDict_SetItemString(dict, "status", PyLong_FromLong(kf->kf_status));
488+
PyDict_SetItemString(dict, "type", PyLong_FromLong(kf->kf_type));
489+
PyDict_SetItemString(dict, "offset", PyLong_FromLongLong(kf->kf_offset));
490+
PyDict_SetItemString(dict, "path", PyBytes_FromString(kf->kf_path));
491+
return dict;
492+
}
493+
494+
PyErr_SetString(PyExc_ValueError, "fcntl.kinfodict could not create its dictionary");
495+
return NULL;
496+
}
497+
498+
#endif
499+
466500
/* List of functions */
467501

468502
static PyMethodDef fcntl_methods[] = {
469503
FCNTL_FCNTL_METHODDEF
470504
FCNTL_IOCTL_METHODDEF
471505
FCNTL_FLOCK_METHODDEF
472506
FCNTL_LOCKF_METHODDEF
507+
FCNTL_KINFOALLOC_METHODDEF
508+
FCNTL_KINFODICT_METHODDEF
473509
{NULL, NULL} /* sentinel */
474510
};
475511

configure

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2701,7 +2701,7 @@ AC_CHECK_HEADERS([ \
27012701
sys/endian.h sys/epoll.h sys/event.h sys/eventfd.h sys/file.h sys/ioctl.h sys/kern_control.h \
27022702
sys/loadavg.h sys/lock.h sys/memfd.h sys/mkdev.h sys/mman.h sys/modem.h sys/param.h sys/poll.h \
27032703
sys/random.h sys/resource.h sys/select.h sys/sendfile.h sys/socket.h sys/soundcard.h sys/stat.h \
2704-
sys/statvfs.h sys/sys_domain.h sys/syscall.h sys/sysmacros.h sys/termio.h sys/time.h sys/times.h \
2704+
sys/statvfs.h sys/sys_domain.h sys/syscall.h sys/sysmacros.h sys/termio.h sys/time.h sys/timerfd.h sys/times.h \
27052705
sys/types.h sys/uio.h sys/un.h sys/user.h sys/utsname.h sys/wait.h sys/xattr.h sysexits.h syslog.h \
27062706
termios.h util.h utime.h utmp.h \
27072707
])

0 commit comments

Comments
 (0)