Skip to content

Commit b23f8ff

Browse files
committed
gh-83714: Set os.statx() members to None if missing from stx_mask
1 parent ea4cc58 commit b23f8ff

File tree

1 file changed

+61
-33
lines changed

1 file changed

+61
-33
lines changed

Modules/posixmodule.c

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3319,6 +3319,8 @@ typedef struct {
33193319
struct statx stx;
33203320
} Py_statx_result;
33213321

3322+
#define Py_statx_result_CAST(op) _Py_CAST(Py_statx_result*, (op))
3323+
33223324
#define M(attr, type, offset, doc) \
33233325
{attr, type, offset, Py_READONLY, PyDoc_STR(doc)}
33243326
#define MM(attr, type, member, doc) \
@@ -3339,10 +3341,6 @@ static PyMemberDef pystatx_result_members[] = {
33393341
MM(st_blocks, Py_T_ULONGLONG, blocks, "number of blocks allocated"),
33403342
MM(stx_attributes_mask, Py_T_ULONGLONG, attributes_mask,
33413343
"Mask of supported bits in stx_attributes"),
3342-
MX(st_atime, Py_T_DOUBLE, atime_sec, "time of last access"),
3343-
MX(st_birthtime, Py_T_DOUBLE, btime_sec, "time of creation"),
3344-
MX(st_ctime, Py_T_DOUBLE, ctime_sec, "time of last change"),
3345-
MX(st_mtime, Py_T_DOUBLE, mtime_sec, "time of last modification"),
33463344
MM(stx_rdev_major, Py_T_UINT, rdev_major, "represented device major number"),
33473345
MM(stx_rdev_minor, Py_T_UINT, rdev_minor, "represented device minor number"),
33483346
MX(st_rdev, Py_T_ULONGLONG, rdev, "device type (if inode device)"),
@@ -3384,31 +3382,59 @@ static PyMemberDef pystatx_result_members[] = {
33843382
#undef MM
33853383
#undef M
33863384

3387-
static PyObject *
3388-
pystatx_result_get_nsec(PyObject *op, void *context)
3389-
{
3390-
uint16_t offset = (uintptr_t)context;
3391-
struct statx_timestamp *ts = (void*)op + offset;
3392-
_posixstate *state = PyType_GetModuleState(Py_TYPE(op));
3393-
assert(state != NULL);
3394-
return stat_nanosecond_timestamp(state, ts->tv_sec, ts->tv_nsec);
3395-
}
33963385

3397-
/* The low 16 bits of the context pointer are the offset from the start of
3398-
Py_statx_result to the struct statx member. */
3399-
#define GM(attr, type, member, doc) \
3400-
{#attr, pystatx_result_get_##type, NULL, PyDoc_STR(doc), \
3401-
(void *)(offsetof(Py_statx_result, stx.stx_##member))}
3386+
#define STATX_GET_DOUBLE(ATTR, MEMBER, MASK) \
3387+
static PyObject* \
3388+
pystatx_result_get_##ATTR(PyObject *op, void *Py_UNUSED(context)) \
3389+
{ \
3390+
Py_statx_result *self = Py_statx_result_CAST(op); \
3391+
if (!(self->stx.stx_mask & MASK)) { \
3392+
Py_RETURN_NONE; \
3393+
} \
3394+
double btime_sec = self->MEMBER; \
3395+
return PyFloat_FromDouble(btime_sec); \
3396+
}
3397+
3398+
STATX_GET_DOUBLE(st_atime, atime_sec, STATX_ATIME)
3399+
STATX_GET_DOUBLE(st_birthtime, btime_sec, STATX_BTIME)
3400+
STATX_GET_DOUBLE(st_ctime, ctime_sec, STATX_CTIME)
3401+
STATX_GET_DOUBLE(st_mtime, mtime_sec, STATX_MTIME)
3402+
3403+
#define STATX_GET_NSEC(ATTR, MEMBER, MASK) \
3404+
static PyObject* \
3405+
pystatx_result_get_##ATTR(PyObject *op, void *context) \
3406+
{ \
3407+
Py_statx_result *self = Py_statx_result_CAST(op); \
3408+
if (!(self->stx.stx_mask & MASK)) { \
3409+
Py_RETURN_NONE; \
3410+
} \
3411+
struct statx_timestamp *ts = &self->stx.MEMBER; \
3412+
_posixstate *state = PyType_GetModuleState(Py_TYPE(op)); \
3413+
assert(state != NULL); \
3414+
return stat_nanosecond_timestamp(state, ts->tv_sec, ts->tv_nsec); \
3415+
}
3416+
3417+
STATX_GET_NSEC(st_atime_ns, stx_atime, STATX_ATIME)
3418+
STATX_GET_NSEC(st_birthtime_ns, stx_atime, STATX_BTIME)
3419+
STATX_GET_NSEC(st_ctime_ns, stx_ctime, STATX_CTIME)
3420+
STATX_GET_NSEC(st_mtime_ns, stx_mtime, STATX_MTIME)
3421+
3422+
#define G(attr, doc) \
3423+
{#attr, pystatx_result_get_##attr, NULL, PyDoc_STR(doc), NULL}
34023424

34033425
static PyGetSetDef pystatx_result_getset[] = {
3404-
GM(st_atime_ns, nsec, atime, "time of last access in nanoseconds"),
3405-
GM(st_birthtime_ns, nsec, btime, "time of creation in nanoseconds"),
3406-
GM(st_ctime_ns, nsec, ctime, "time of last change in nanoseconds"),
3407-
GM(st_mtime_ns, nsec, mtime, "time of last modification in nanoseconds"),
3426+
G(st_atime, "time of last access"),
3427+
G(st_birthtime, "time of creation"),
3428+
G(st_ctime, "time of last modification"),
3429+
G(st_mtime, "time of last modification"),
3430+
G(st_atime_ns, "time of last access in nanoseconds"),
3431+
G(st_birthtime_ns, "time of creation in nanoseconds"),
3432+
G(st_ctime_ns, "time of last change in nanoseconds"),
3433+
G(st_mtime_ns, "time of last modification in nanoseconds"),
34083434
{NULL},
34093435
};
34103436

3411-
#undef GM
3437+
#undef G
34123438

34133439
static PyObject *
34143440
pystatx_result_repr(PyObject *op)
@@ -3452,23 +3478,25 @@ pystatx_result_repr(PyObject *op)
34523478
}
34533479

34543480
for (size_t i = 0; i < Py_ARRAY_LENGTH(pystatx_result_getset) - 1; ++i) {
3455-
if (i > 0) {
3456-
WRITE_ASCII(", ");
3457-
}
3458-
34593481
PyGetSetDef *d = &pystatx_result_getset[i];
3460-
WRITE_ASCII(d->name);
3461-
WRITE_ASCII("=");
3462-
34633482
PyObject *o = d->get(op, d->closure);
34643483
if (o == NULL) {
34653484
goto error;
34663485
}
3467-
if (PyUnicodeWriter_WriteRepr(writer, o) < 0) {
3486+
3487+
if (o != Py_None) {
3488+
if (i > 0) {
3489+
WRITE_ASCII(", ");
3490+
}
3491+
3492+
WRITE_ASCII(d->name);
3493+
WRITE_ASCII("=");
3494+
if (PyUnicodeWriter_WriteRepr(writer, o) < 0) {
3495+
Py_DECREF(o);
3496+
goto error;
3497+
}
34683498
Py_DECREF(o);
3469-
goto error;
34703499
}
3471-
Py_DECREF(o);
34723500
}
34733501

34743502
WRITE_ASCII(")");

0 commit comments

Comments
 (0)