struct stat

Updated: April 19, 2023

The struct stat is different in 64-bit architectures than in 32-bit ones because it includes 64-bit time_t members. POSIX 2008 added support for nanosecond-resolution timestamps (st_mtim, st_atim, and st_ctim fields are of type struct timespec). This means that there are several forms of the stat structure:

struct __stat_t32_2001
Includes 32-bit time_t fields, but not the nanosecond-resolution timestamps. This is what earlier versions of the OS supported and is the default for 32-bit architectures.
struct __stat_t32_2008
Includes 32-bit time_t fields, and the nanosecond-resolution timestamps.
struct __stat_t64_2008
Includes 64-bit time_t fields, and the nanosecond-resolution timestamps. This is the default for 64-bit architectures.

The dirent_extra_stat information (see readdir()) also handles the different stat formats. The dirent_extra_type enumerated type, which defines the possible values for the d_type member, is defined as follows:

enum dirent_extra_type {
	_DTYPE_NONE,
	_DTYPE_STAT_UNSET,
	_DTYPE_LSTAT_UNSET,
	_DTYPE_STAT_T32_2001,
	_DTYPE_LSTAT_T32_2001,
	_DTYPE_STAT_T32_2008,
	_DTYPE_LSTAT_T32_2008,
	_DTYPE_STAT_T64_2008,
	_DTYPE_LSTAT_T64_2008,
#if __PTR_BITS__ == 32
	_DTYPE_STAT = _DTYPE_STAT_T32_2001,
	_DTYPE_LSTAT = _DTYPE_LSTAT_T32_2001,
#else
	_DTYPE_STAT = _DTYPE_STAT_T64_2008,
	_DTYPE_LSTAT = _DTYPE_LSTAT_T64_2008,
#endif
};

As before, the _DTYPE_STAT* types indicate that the resource manager didn't resolve symbolic links, and the _DTYPE_LSTAT* types indicate that the resource manager did. _DTYPE_STAT_UNSET and _DTYPE_LSTAT_UNSET correspond to the former values of _DTYPE_STAT and _DTYPE_LSTAT; the others also indicate which form of the stat structure is included.

You can use stat_convert_form() to convert one form of a struct stat into another.

There are several different sets of constants for identifying the formats of the stat structure:

dircntl()
Use these flags (defined in <dirent.h>) to indicate which form of stat structure you want returned with readdir():
#define D_FLAG_STAT     0x00000002      /* Attempt to return extra stat information */
#define D_FLAG_STAT_FORM_UNSET          0x00000000      /* == _STAT_FORM_UNSET */
#define D_FLAG_STAT_FORM_T32_2001       0x00000010      /* want _STAT_FORM_T32_2001 */
#define D_FLAG_STAT_FORM_T32_2008       0x00000020      /* want _STAT_FORM_T32_2008 */
#define D_FLAG_STAT_FORM_T64_2008       0x00000030      /* want _STAT_FORM_T32_2008 */
  

There's a mask too:

#define D_FLAG_STAT_FORM_MASK 0x000000f0
  

If you set a D_FLAG_STAT_FORM_* flag, it's ORed into the current flags for the directory; otherwise, the flags you pass to dircntl() replace the directory's flags. The D_FLAG_STAT_FORM_* values are the corresponding _STAT_FORM_* values shifted up four bits.

_readdir_r()
If D_FLAG_STAT is set, set _IO_XFLAG_DIR_EXTRA_HINT in the _IO_READ message's xtype.

If D_FLAG_STAT_FORM_* is set, set the appropriate one of the following (from <sys/iomsg.h>) in the _IO_READ message:

_IO_XFLAG_DIR_STAT_FORM_UNSET    = 0x00000000,
_IO_XFLAG_DIR_STAT_FORM_T32_2001 = 0x00010000,
_IO_XFLAG_DIR_STAT_FORM_T32_2008 = 0x00020000,
_IO_XFLAG_DIR_STAT_FORM_T64_2008 = 0x00030000,
  

There's a mask too:

_IO_XFLAG_DIR_STAT_FORM_MASK     = 0x000f0000,
  
_IO_READ handler
Append the appropriate form of the stat structure to the message, setting d_type (in dirent_extra_stat) to one of the following (from <dirent.h>):
enum dirent_extra_type {
        _DTYPE_NONE,
        _DTYPE_STAT_UNSET,
        _DTYPE_LSTAT_UNSET,
        _DTYPE_STAT_T32_2001,
        _DTYPE_LSTAT_T32_2001,
        _DTYPE_STAT_T32_2008,
        _DTYPE_LSTAT_T32_2008,
        _DTYPE_STAT_T64_2008,
        _DTYPE_LSTAT_T64_2008,
#if __PTR_BITS__ == 32
        _DTYPE_STAT = _DTYPE_STAT_T32_2001,
        _DTYPE_LSTAT = _DTYPE_LSTAT_T32_2001,
#else
        _DTYPE_STAT = _DTYPE_STAT_T64_2008,
        _DTYPE_LSTAT = _DTYPE_LSTAT_T64_2008,
#endif
};
  
_IO_STAT messages
Choose the appropriate type (from <sys/stat.h>):
#define _STAT_FORM_UNSET        0
#define _STAT_FORM_T32_2001     1
#define _STAT_FORM_T32_2008     2
#define _STAT_FORM_T64_2008     3
#if __PTR_BITS__ == 32
#define _STAT_FORM_SYS_2008             (_STAT_FORM_T32_2008)
#define _STAT_FORM_PREFERRED    (_STAT_FORM_T32_2001)
#else
#define _STAT_FORM_SYS_2008             (_STAT_FORM_T64_2008)
#define _STAT_FORM_PREFERRED    (_STAT_FORM_T64_2008)
#endif
  

There's a mask too:

#define _STAT_FORM_MASK         0x03u
  

The handler returns, via the status argument to MsgReply(), the format that was generated.