Consider the following two API variants:
struct point get_location(const foo *f)
{
    struct point p;
    p.x = f->something_x;
    p.y = f->something_y;
    return p;
}
versus:
double get_location_x(const foo *f)
{
    return f->something_x;
}
double get_location_y(const foo *f)
{
    return f->something_y;
}
I claim there is nothing “more encapsulated” about the latter than the former.  It’s just a matter of perspective whether you consider the result type of the former to be a value type. Likewise, struct dirent is a value type whose definition is well-specified and stable/fixed. As @Jean-FrançoisFabre51 commented, it is the result value that’s obtained from some internal state encapsulated in the DIR object.
5
solved Why some C API doesn’t follow Encapsulation