(root)/
Python-3.12.0/
Modules/
_stat.c
       1  /* stat.h interface
       2   *
       3   * The module defines all S_IF*, S_I*, UF_*, SF_* and ST_* constants to
       4   * sensible default values as well as defines S_IS*() macros in order to keep
       5   * backward compatibility with the old stat.py module.
       6   *
       7   * New constants and macros such as S_IFDOOR / S_ISDOOR() are always defined
       8   * as int 0.
       9   *
      10   * NOTE: POSIX only defines the values of the S_I* permission bits.
      11   *
      12   */
      13  
      14  #define PY_SSIZE_T_CLEAN
      15  #include "Python.h"
      16  
      17  #ifdef __cplusplus
      18  extern "C" {
      19  #endif
      20  
      21  #ifdef HAVE_SYS_TYPES_H
      22  #include <sys/types.h>
      23  #endif /* HAVE_SYS_TYPES_H */
      24  
      25  #ifdef HAVE_SYS_STAT_H
      26  #include <sys/stat.h>
      27  #endif /* HAVE_SYS_STAT_H */
      28  
      29  #ifdef MS_WINDOWS
      30  #include <windows.h>
      31  typedef unsigned short mode_t;
      32  
      33  /* FILE_ATTRIBUTE_INTEGRITY_STREAM and FILE_ATTRIBUTE_NO_SCRUB_DATA
      34     are not present in VC2010, so define them manually */
      35  #ifndef FILE_ATTRIBUTE_INTEGRITY_STREAM
      36  #  define FILE_ATTRIBUTE_INTEGRITY_STREAM 0x8000
      37  #endif
      38  
      39  #ifndef FILE_ATTRIBUTE_NO_SCRUB_DATA
      40  #  define FILE_ATTRIBUTE_NO_SCRUB_DATA 0x20000
      41  #endif
      42  
      43  #ifndef IO_REPARSE_TAG_APPEXECLINK
      44  #  define IO_REPARSE_TAG_APPEXECLINK 0x8000001BL
      45  #endif
      46  
      47  #endif /* MS_WINDOWS */
      48  
      49  /* From Python's stat.py */
      50  #ifndef S_IMODE
      51  #  define S_IMODE 07777
      52  #endif
      53  
      54  /* S_IFXXX constants (file types)
      55   *
      56   * Only the names are defined by POSIX but not their value. All common file
      57   * types seems to have the same numeric value on all platforms, though.
      58   *
      59   * pyport.h guarantees S_IFMT, S_IFDIR, S_IFCHR, S_IFREG and S_IFLNK
      60   */
      61  
      62  #ifndef S_IFBLK
      63  #  define S_IFBLK 0060000
      64  #endif
      65  
      66  #ifndef S_IFIFO
      67  #  define S_IFIFO 0010000
      68  #endif
      69  
      70  #ifndef S_IFSOCK
      71  #  define S_IFSOCK 0140000
      72  #endif
      73  
      74  #ifndef S_IFDOOR
      75  #  define S_IFDOOR 0
      76  #endif
      77  
      78  #ifndef S_IFPORT
      79  #  define S_IFPORT 0
      80  #endif
      81  
      82  #ifndef S_IFWHT
      83  #  define S_IFWHT 0
      84  #endif
      85  
      86  
      87  /* S_ISXXX()
      88   * pyport.h defines S_ISDIR(), S_ISREG() and S_ISCHR()
      89   */
      90  
      91  #ifndef S_ISBLK
      92  #  define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
      93  #endif
      94  
      95  #ifndef S_ISFIFO
      96  #  define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
      97  #endif
      98  
      99  #ifndef S_ISLNK
     100  #  define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
     101  #endif
     102  
     103  #ifndef S_ISSOCK
     104  #  define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
     105  #endif
     106  
     107  #ifndef S_ISDOOR
     108  #  define S_ISDOOR(mode) 0
     109  #endif
     110  
     111  #ifndef S_ISPORT
     112  #  define S_ISPORT(mode) 0
     113  #endif
     114  
     115  #ifndef S_ISWHT
     116  #  define S_ISWHT(mode) 0
     117  #endif
     118  
     119  
     120  /* S_I* file permission
     121   *
     122   * The permission bit value are defined by POSIX standards.
     123   */
     124  #ifndef S_ISUID
     125  #  define S_ISUID 04000
     126  #endif
     127  
     128  #ifndef S_ISGID
     129  #  define S_ISGID 02000
     130  #endif
     131  
     132  /* what is S_ENFMT? */
     133  #ifndef S_ENFMT
     134  #  define S_ENFMT S_ISGID
     135  #endif
     136  
     137  #ifndef S_ISVTX
     138  #  define S_ISVTX 01000
     139  #endif
     140  
     141  #ifndef S_IREAD
     142  #  define S_IREAD 00400
     143  #endif
     144  
     145  #ifndef S_IWRITE
     146  #  define S_IWRITE 00200
     147  #endif
     148  
     149  #ifndef S_IEXEC
     150  #  define S_IEXEC 00100
     151  #endif
     152  
     153  #ifndef S_IRWXU
     154  #  define S_IRWXU 00700
     155  #endif
     156  
     157  #ifndef S_IRUSR
     158  #  define S_IRUSR 00400
     159  #endif
     160  
     161  #ifndef S_IWUSR
     162  #  define S_IWUSR 00200
     163  #endif
     164  
     165  #ifndef S_IXUSR
     166  #  define S_IXUSR 00100
     167  #endif
     168  
     169  #ifndef S_IRWXG
     170  #  define S_IRWXG 00070
     171  #endif
     172  
     173  #ifndef S_IRGRP
     174  #  define S_IRGRP 00040
     175  #endif
     176  
     177  #ifndef S_IWGRP
     178  #  define S_IWGRP 00020
     179  #endif
     180  
     181  #ifndef S_IXGRP
     182  #  define S_IXGRP 00010
     183  #endif
     184  
     185  #ifndef S_IRWXO
     186  #  define S_IRWXO 00007
     187  #endif
     188  
     189  #ifndef S_IROTH
     190  #  define S_IROTH 00004
     191  #endif
     192  
     193  #ifndef S_IWOTH
     194  #  define S_IWOTH 00002
     195  #endif
     196  
     197  #ifndef S_IXOTH
     198  #  define S_IXOTH 00001
     199  #endif
     200  
     201  
     202  /* Names for file flags */
     203  #ifndef UF_NODUMP
     204  #  define UF_NODUMP 0x00000001
     205  #endif
     206  
     207  #ifndef UF_IMMUTABLE
     208  #  define UF_IMMUTABLE 0x00000002
     209  #endif
     210  
     211  #ifndef UF_APPEND
     212  #  define UF_APPEND 0x00000004
     213  #endif
     214  
     215  #ifndef UF_OPAQUE
     216  #  define UF_OPAQUE 0x00000008
     217  #endif
     218  
     219  #ifndef UF_NOUNLINK
     220  #  define UF_NOUNLINK 0x00000010
     221  #endif
     222  
     223  #ifndef UF_COMPRESSED
     224  #  define UF_COMPRESSED 0x00000020
     225  #endif
     226  
     227  #ifndef UF_HIDDEN
     228  #  define UF_HIDDEN 0x00008000
     229  #endif
     230  
     231  #ifndef SF_ARCHIVED
     232  #  define SF_ARCHIVED 0x00010000
     233  #endif
     234  
     235  #ifndef SF_IMMUTABLE
     236  #  define SF_IMMUTABLE 0x00020000
     237  #endif
     238  
     239  #ifndef SF_APPEND
     240  #  define SF_APPEND 0x00040000
     241  #endif
     242  
     243  #ifndef SF_NOUNLINK
     244  #  define SF_NOUNLINK 0x00100000
     245  #endif
     246  
     247  #ifndef SF_SNAPSHOT
     248  #  define SF_SNAPSHOT 0x00200000
     249  #endif
     250  
     251  static mode_t
     252  _PyLong_AsMode_t(PyObject *op)
     253  {
     254      unsigned long value;
     255      mode_t mode;
     256  
     257      value = PyLong_AsUnsignedLong(op);
     258      if ((value == (unsigned long)-1) && PyErr_Occurred())
     259          return (mode_t)-1;
     260  
     261      mode = (mode_t)value;
     262      if ((unsigned long)mode != value) {
     263          PyErr_SetString(PyExc_OverflowError, "mode out of range");
     264          return (mode_t)-1;
     265      }
     266      return mode;
     267  }
     268  
     269  
     270  #define stat_S_ISFUNC(isfunc, doc)                             \
     271      static PyObject *                                          \
     272      stat_ ##isfunc (PyObject *self, PyObject *omode)           \
     273      {                                                          \
     274         mode_t mode = _PyLong_AsMode_t(omode);                   \
     275         if ((mode == (mode_t)-1) && PyErr_Occurred())           \
     276             return NULL;                                        \
     277         return PyBool_FromLong(isfunc(mode));                   \
     278      }                                                          \
     279      PyDoc_STRVAR(stat_ ## isfunc ## _doc, doc)
     280  
     281  stat_S_ISFUNC(S_ISDIR,
     282      "S_ISDIR(mode) -> bool\n\n"
     283      "Return True if mode is from a directory.");
     284  
     285  stat_S_ISFUNC(S_ISCHR,
     286      "S_ISCHR(mode) -> bool\n\n"
     287      "Return True if mode is from a character special device file.");
     288  
     289  stat_S_ISFUNC(S_ISBLK,
     290      "S_ISBLK(mode) -> bool\n\n"
     291      "Return True if mode is from a block special device file.");
     292  
     293  stat_S_ISFUNC(S_ISREG,
     294      "S_ISREG(mode) -> bool\n\n"
     295      "Return True if mode is from a regular file.");
     296  
     297  stat_S_ISFUNC(S_ISFIFO,
     298      "S_ISFIFO(mode) -> bool\n\n"
     299      "Return True if mode is from a FIFO (named pipe).");
     300  
     301  stat_S_ISFUNC(S_ISLNK,
     302      "S_ISLNK(mode) -> bool\n\n"
     303      "Return True if mode is from a symbolic link.");
     304  
     305  stat_S_ISFUNC(S_ISSOCK,
     306      "S_ISSOCK(mode) -> bool\n\n"
     307      "Return True if mode is from a socket.");
     308  
     309  stat_S_ISFUNC(S_ISDOOR,
     310      "S_ISDOOR(mode) -> bool\n\n"
     311      "Return True if mode is from a door.");
     312  
     313  stat_S_ISFUNC(S_ISPORT,
     314      "S_ISPORT(mode) -> bool\n\n"
     315      "Return True if mode is from an event port.");
     316  
     317  stat_S_ISFUNC(S_ISWHT,
     318      "S_ISWHT(mode) -> bool\n\n"
     319      "Return True if mode is from a whiteout.");
     320  
     321  
     322  PyDoc_STRVAR(stat_S_IMODE_doc,
     323  "Return the portion of the file's mode that can be set by os.chmod().");
     324  
     325  static PyObject *
     326  stat_S_IMODE(PyObject *self, PyObject *omode)
     327  {
     328      mode_t mode = _PyLong_AsMode_t(omode);
     329      if ((mode == (mode_t)-1) && PyErr_Occurred())
     330          return NULL;
     331      return PyLong_FromUnsignedLong(mode & S_IMODE);
     332  }
     333  
     334  
     335  PyDoc_STRVAR(stat_S_IFMT_doc,
     336  "Return the portion of the file's mode that describes the file type.");
     337  
     338  static PyObject *
     339  stat_S_IFMT(PyObject *self, PyObject *omode)
     340  {
     341      mode_t mode = _PyLong_AsMode_t(omode);
     342      if ((mode == (mode_t)-1) && PyErr_Occurred())
     343          return NULL;
     344      return PyLong_FromUnsignedLong(mode & S_IFMT);
     345  }
     346  
     347  /* file type chars according to
     348     http://en.wikibooks.org/wiki/C_Programming/POSIX_Reference/sys/stat.h */
     349  
     350  static char
     351  filetype(mode_t mode)
     352  {
     353      /* common cases first */
     354      if (S_ISREG(mode))  return '-';
     355      if (S_ISDIR(mode))  return 'd';
     356      if (S_ISLNK(mode))  return 'l';
     357      /* special files */
     358      if (S_ISBLK(mode))  return 'b';
     359      if (S_ISCHR(mode))  return 'c';
     360      if (S_ISFIFO(mode)) return 'p';
     361      if (S_ISSOCK(mode)) return 's';
     362      /* non-standard types */
     363      if (S_ISDOOR(mode)) return 'D';
     364      if (S_ISPORT(mode)) return 'P';
     365      if (S_ISWHT(mode))  return 'w';
     366      /* unknown */
     367      return '?';
     368  }
     369  
     370  static void
     371  fileperm(mode_t mode, char *buf)
     372  {
     373      buf[0] = mode & S_IRUSR ? 'r' : '-';
     374      buf[1] = mode & S_IWUSR ? 'w' : '-';
     375      if (mode & S_ISUID) {
     376          buf[2] = mode & S_IXUSR ? 's' : 'S';
     377      } else {
     378          buf[2] = mode & S_IXUSR ? 'x' : '-';
     379      }
     380      buf[3] = mode & S_IRGRP ? 'r' : '-';
     381      buf[4] = mode & S_IWGRP ? 'w' : '-';
     382      if (mode & S_ISGID) {
     383          buf[5] = mode & S_IXGRP ? 's' : 'S';
     384      } else {
     385          buf[5] = mode & S_IXGRP ? 'x' : '-';
     386      }
     387      buf[6] = mode & S_IROTH ? 'r' : '-';
     388      buf[7] = mode & S_IWOTH ? 'w' : '-';
     389      if (mode & S_ISVTX) {
     390          buf[8] = mode & S_IXOTH ? 't' : 'T';
     391      } else {
     392          buf[8] = mode & S_IXOTH ? 'x' : '-';
     393      }
     394  }
     395  
     396  PyDoc_STRVAR(stat_filemode_doc,
     397  "Convert a file's mode to a string of the form '-rwxrwxrwx'");
     398  
     399  static PyObject *
     400  stat_filemode(PyObject *self, PyObject *omode)
     401  {
     402      char buf[10];
     403      mode_t mode;
     404  
     405      mode = _PyLong_AsMode_t(omode);
     406      if ((mode == (mode_t)-1) && PyErr_Occurred())
     407          return NULL;
     408  
     409      buf[0] = filetype(mode);
     410      fileperm(mode, &buf[1]);
     411      return PyUnicode_FromStringAndSize(buf, 10);
     412  }
     413  
     414  
     415  static PyMethodDef stat_methods[] = {
     416      {"S_ISDIR",         stat_S_ISDIR,  METH_O, stat_S_ISDIR_doc},
     417      {"S_ISCHR",         stat_S_ISCHR,  METH_O, stat_S_ISCHR_doc},
     418      {"S_ISBLK",         stat_S_ISBLK,  METH_O, stat_S_ISBLK_doc},
     419      {"S_ISREG",         stat_S_ISREG,  METH_O, stat_S_ISREG_doc},
     420      {"S_ISFIFO",        stat_S_ISFIFO, METH_O, stat_S_ISFIFO_doc},
     421      {"S_ISLNK",         stat_S_ISLNK,  METH_O, stat_S_ISLNK_doc},
     422      {"S_ISSOCK",        stat_S_ISSOCK, METH_O, stat_S_ISSOCK_doc},
     423      {"S_ISDOOR",        stat_S_ISDOOR, METH_O, stat_S_ISDOOR_doc},
     424      {"S_ISPORT",        stat_S_ISPORT, METH_O, stat_S_ISPORT_doc},
     425      {"S_ISWHT",         stat_S_ISWHT,  METH_O, stat_S_ISWHT_doc},
     426      {"S_IMODE",         stat_S_IMODE,  METH_O, stat_S_IMODE_doc},
     427      {"S_IFMT",          stat_S_IFMT,   METH_O, stat_S_IFMT_doc},
     428      {"filemode",        stat_filemode, METH_O, stat_filemode_doc},
     429      {NULL,              NULL}           /* sentinel */
     430  };
     431  
     432  
     433  PyDoc_STRVAR(module_doc,
     434  "S_IFMT_: file type bits\n\
     435  S_IFDIR: directory\n\
     436  S_IFCHR: character device\n\
     437  S_IFBLK: block device\n\
     438  S_IFREG: regular file\n\
     439  S_IFIFO: fifo (named pipe)\n\
     440  S_IFLNK: symbolic link\n\
     441  S_IFSOCK: socket file\n\
     442  S_IFDOOR: door\n\
     443  S_IFPORT: event port\n\
     444  S_IFWHT: whiteout\n\
     445  \n"
     446  
     447  "S_ISUID: set UID bit\n\
     448  S_ISGID: set GID bit\n\
     449  S_ENFMT: file locking enforcement\n\
     450  S_ISVTX: sticky bit\n\
     451  S_IREAD: Unix V7 synonym for S_IRUSR\n\
     452  S_IWRITE: Unix V7 synonym for S_IWUSR\n\
     453  S_IEXEC: Unix V7 synonym for S_IXUSR\n\
     454  S_IRWXU: mask for owner permissions\n\
     455  S_IRUSR: read by owner\n\
     456  S_IWUSR: write by owner\n\
     457  S_IXUSR: execute by owner\n\
     458  S_IRWXG: mask for group permissions\n\
     459  S_IRGRP: read by group\n\
     460  S_IWGRP: write by group\n\
     461  S_IXGRP: execute by group\n\
     462  S_IRWXO: mask for others (not in group) permissions\n\
     463  S_IROTH: read by others\n\
     464  S_IWOTH: write by others\n\
     465  S_IXOTH: execute by others\n\
     466  \n"
     467  
     468  "UF_NODUMP: do not dump file\n\
     469  UF_IMMUTABLE: file may not be changed\n\
     470  UF_APPEND: file may only be appended to\n\
     471  UF_OPAQUE: directory is opaque when viewed through a union stack\n\
     472  UF_NOUNLINK: file may not be renamed or deleted\n\
     473  UF_COMPRESSED: OS X: file is hfs-compressed\n\
     474  UF_HIDDEN: OS X: file should not be displayed\n\
     475  SF_ARCHIVED: file may be archived\n\
     476  SF_IMMUTABLE: file may not be changed\n\
     477  SF_APPEND: file may only be appended to\n\
     478  SF_NOUNLINK: file may not be renamed or deleted\n\
     479  SF_SNAPSHOT: file is a snapshot file\n\
     480  \n"
     481  
     482  "ST_MODE\n\
     483  ST_INO\n\
     484  ST_DEV\n\
     485  ST_NLINK\n\
     486  ST_UID\n\
     487  ST_GID\n\
     488  ST_SIZE\n\
     489  ST_ATIME\n\
     490  ST_MTIME\n\
     491  ST_CTIME\n\
     492  \n"
     493  
     494  "FILE_ATTRIBUTE_*: Windows file attribute constants\n\
     495                     (only present on Windows)\n\
     496  ");
     497  
     498  
     499  static int
     500  stat_exec(PyObject *module)
     501  {
     502  #define ADD_INT_MACRO(module, macro)                                  \
     503      do {                                                              \
     504          if (PyModule_AddIntConstant(module, #macro, macro) < 0) {     \
     505              return -1;                                                \
     506          }                                                             \
     507      } while (0)
     508  
     509      ADD_INT_MACRO(module, S_IFDIR);
     510      ADD_INT_MACRO(module, S_IFCHR);
     511      ADD_INT_MACRO(module, S_IFBLK);
     512      ADD_INT_MACRO(module, S_IFREG);
     513      ADD_INT_MACRO(module, S_IFIFO);
     514      ADD_INT_MACRO(module, S_IFLNK);
     515      ADD_INT_MACRO(module, S_IFSOCK);
     516      ADD_INT_MACRO(module, S_IFDOOR);
     517      ADD_INT_MACRO(module, S_IFPORT);
     518      ADD_INT_MACRO(module, S_IFWHT);
     519  
     520      ADD_INT_MACRO(module, S_ISUID);
     521      ADD_INT_MACRO(module, S_ISGID);
     522      ADD_INT_MACRO(module, S_ISVTX);
     523      ADD_INT_MACRO(module, S_ENFMT);
     524  
     525      ADD_INT_MACRO(module, S_IREAD);
     526      ADD_INT_MACRO(module, S_IWRITE);
     527      ADD_INT_MACRO(module, S_IEXEC);
     528  
     529      ADD_INT_MACRO(module, S_IRWXU);
     530      ADD_INT_MACRO(module, S_IRUSR);
     531      ADD_INT_MACRO(module, S_IWUSR);
     532      ADD_INT_MACRO(module, S_IXUSR);
     533  
     534      ADD_INT_MACRO(module, S_IRWXG);
     535      ADD_INT_MACRO(module, S_IRGRP);
     536      ADD_INT_MACRO(module, S_IWGRP);
     537      ADD_INT_MACRO(module, S_IXGRP);
     538  
     539      ADD_INT_MACRO(module, S_IRWXO);
     540      ADD_INT_MACRO(module, S_IROTH);
     541      ADD_INT_MACRO(module, S_IWOTH);
     542      ADD_INT_MACRO(module, S_IXOTH);
     543  
     544      ADD_INT_MACRO(module, UF_NODUMP);
     545      ADD_INT_MACRO(module, UF_IMMUTABLE);
     546      ADD_INT_MACRO(module, UF_APPEND);
     547      ADD_INT_MACRO(module, UF_OPAQUE);
     548      ADD_INT_MACRO(module, UF_NOUNLINK);
     549      ADD_INT_MACRO(module, UF_COMPRESSED);
     550      ADD_INT_MACRO(module, UF_HIDDEN);
     551      ADD_INT_MACRO(module, SF_ARCHIVED);
     552      ADD_INT_MACRO(module, SF_IMMUTABLE);
     553      ADD_INT_MACRO(module, SF_APPEND);
     554      ADD_INT_MACRO(module, SF_NOUNLINK);
     555      ADD_INT_MACRO(module, SF_SNAPSHOT);
     556  
     557      const char* st_constants[] = {
     558          "ST_MODE",
     559          "ST_INO",
     560          "ST_DEV",
     561          "ST_NLINK",
     562          "ST_UID",
     563          "ST_GID",
     564          "ST_SIZE",
     565          "ST_ATIME",
     566          "ST_MTIME",
     567          "ST_CTIME"
     568      };
     569  
     570      for (int i = 0; i < (int)Py_ARRAY_LENGTH(st_constants); i++) {
     571          if (PyModule_AddIntConstant(module, st_constants[i], i) < 0) {
     572              return -1;
     573          }
     574      }
     575  
     576  #ifdef MS_WINDOWS
     577      ADD_INT_MACRO(module, FILE_ATTRIBUTE_ARCHIVE);
     578      ADD_INT_MACRO(module, FILE_ATTRIBUTE_COMPRESSED);
     579      ADD_INT_MACRO(module, FILE_ATTRIBUTE_DEVICE);
     580      ADD_INT_MACRO(module, FILE_ATTRIBUTE_DIRECTORY);
     581      ADD_INT_MACRO(module, FILE_ATTRIBUTE_ENCRYPTED);
     582      ADD_INT_MACRO(module, FILE_ATTRIBUTE_HIDDEN);
     583      ADD_INT_MACRO(module, FILE_ATTRIBUTE_INTEGRITY_STREAM);
     584      ADD_INT_MACRO(module, FILE_ATTRIBUTE_NORMAL);
     585      ADD_INT_MACRO(module, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
     586      ADD_INT_MACRO(module, FILE_ATTRIBUTE_NO_SCRUB_DATA);
     587      ADD_INT_MACRO(module, FILE_ATTRIBUTE_OFFLINE);
     588      ADD_INT_MACRO(module, FILE_ATTRIBUTE_READONLY);
     589      ADD_INT_MACRO(module, FILE_ATTRIBUTE_REPARSE_POINT);
     590      ADD_INT_MACRO(module, FILE_ATTRIBUTE_SPARSE_FILE);
     591      ADD_INT_MACRO(module, FILE_ATTRIBUTE_SYSTEM);
     592      ADD_INT_MACRO(module, FILE_ATTRIBUTE_TEMPORARY);
     593      ADD_INT_MACRO(module, FILE_ATTRIBUTE_VIRTUAL);
     594  
     595      if (_PyModule_Add(module, "IO_REPARSE_TAG_SYMLINK",
     596              PyLong_FromUnsignedLong(IO_REPARSE_TAG_SYMLINK)) < 0) {
     597          return -1;
     598      }
     599      if (_PyModule_Add(module, "IO_REPARSE_TAG_MOUNT_POINT",
     600              PyLong_FromUnsignedLong(IO_REPARSE_TAG_MOUNT_POINT)) < 0) {
     601          return -1;
     602      }
     603      if (_PyModule_Add(module, "IO_REPARSE_TAG_APPEXECLINK",
     604              PyLong_FromUnsignedLong(IO_REPARSE_TAG_APPEXECLINK)) < 0) {
     605          return -1;
     606      }
     607  #endif
     608  
     609      return 0;
     610  }
     611  
     612  
     613  static PyModuleDef_Slot stat_slots[] = {
     614      {Py_mod_exec, stat_exec},
     615      {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
     616      {0, NULL}
     617  };
     618  
     619  
     620  static struct PyModuleDef statmodule = {
     621      PyModuleDef_HEAD_INIT,
     622      .m_name = "_stat",
     623      .m_doc = module_doc,
     624      .m_size = 0,
     625      .m_methods = stat_methods,
     626      .m_slots = stat_slots,
     627  };
     628  
     629  
     630  PyMODINIT_FUNC
     631  PyInit__stat(void)
     632  {
     633      return PyModuleDef_Init(&statmodule);
     634  }
     635  
     636  #ifdef __cplusplus
     637  }
     638  #endif