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
_PyLong_AsMode_t(PyObject * op)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 *
stat_S_IMODE(PyObject * self,PyObject * omode)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 *
stat_S_IFMT(PyObject * self,PyObject * omode)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
filetype(mode_t mode)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
fileperm(mode_t mode,char * buf)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 *
stat_filemode(PyObject * self,PyObject * omode)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 struct PyModuleDef statmodule = {
500     PyModuleDef_HEAD_INIT,
501     "_stat",
502     module_doc,
503     -1,
504     stat_methods,
505     NULL,
506     NULL,
507     NULL,
508     NULL
509 };
510 
511 PyMODINIT_FUNC
PyInit__stat(void)512 PyInit__stat(void)
513 {
514     PyObject *m;
515     m = PyModule_Create(&statmodule);
516     if (m == NULL)
517         return NULL;
518 
519     if (PyModule_AddIntMacro(m, S_IFDIR)) return NULL;
520     if (PyModule_AddIntMacro(m, S_IFCHR)) return NULL;
521     if (PyModule_AddIntMacro(m, S_IFBLK)) return NULL;
522     if (PyModule_AddIntMacro(m, S_IFREG)) return NULL;
523     if (PyModule_AddIntMacro(m, S_IFIFO)) return NULL;
524     if (PyModule_AddIntMacro(m, S_IFLNK)) return NULL;
525     if (PyModule_AddIntMacro(m, S_IFSOCK)) return NULL;
526     if (PyModule_AddIntMacro(m, S_IFDOOR)) return NULL;
527     if (PyModule_AddIntMacro(m, S_IFPORT)) return NULL;
528     if (PyModule_AddIntMacro(m, S_IFWHT)) return NULL;
529 
530     if (PyModule_AddIntMacro(m, S_ISUID)) return NULL;
531     if (PyModule_AddIntMacro(m, S_ISGID)) return NULL;
532     if (PyModule_AddIntMacro(m, S_ISVTX)) return NULL;
533     if (PyModule_AddIntMacro(m, S_ENFMT)) return NULL;
534 
535     if (PyModule_AddIntMacro(m, S_IREAD)) return NULL;
536     if (PyModule_AddIntMacro(m, S_IWRITE)) return NULL;
537     if (PyModule_AddIntMacro(m, S_IEXEC)) return NULL;
538 
539     if (PyModule_AddIntMacro(m, S_IRWXU)) return NULL;
540     if (PyModule_AddIntMacro(m, S_IRUSR)) return NULL;
541     if (PyModule_AddIntMacro(m, S_IWUSR)) return NULL;
542     if (PyModule_AddIntMacro(m, S_IXUSR)) return NULL;
543 
544     if (PyModule_AddIntMacro(m, S_IRWXG)) return NULL;
545     if (PyModule_AddIntMacro(m, S_IRGRP)) return NULL;
546     if (PyModule_AddIntMacro(m, S_IWGRP)) return NULL;
547     if (PyModule_AddIntMacro(m, S_IXGRP)) return NULL;
548 
549     if (PyModule_AddIntMacro(m, S_IRWXO)) return NULL;
550     if (PyModule_AddIntMacro(m, S_IROTH)) return NULL;
551     if (PyModule_AddIntMacro(m, S_IWOTH)) return NULL;
552     if (PyModule_AddIntMacro(m, S_IXOTH)) return NULL;
553 
554     if (PyModule_AddIntMacro(m, UF_NODUMP)) return NULL;
555     if (PyModule_AddIntMacro(m, UF_IMMUTABLE)) return NULL;
556     if (PyModule_AddIntMacro(m, UF_APPEND)) return NULL;
557     if (PyModule_AddIntMacro(m, UF_OPAQUE)) return NULL;
558     if (PyModule_AddIntMacro(m, UF_NOUNLINK)) return NULL;
559     if (PyModule_AddIntMacro(m, UF_COMPRESSED)) return NULL;
560     if (PyModule_AddIntMacro(m, UF_HIDDEN)) return NULL;
561     if (PyModule_AddIntMacro(m, SF_ARCHIVED)) return NULL;
562     if (PyModule_AddIntMacro(m, SF_IMMUTABLE)) return NULL;
563     if (PyModule_AddIntMacro(m, SF_APPEND)) return NULL;
564     if (PyModule_AddIntMacro(m, SF_NOUNLINK)) return NULL;
565     if (PyModule_AddIntMacro(m, SF_SNAPSHOT)) return NULL;
566 
567     if (PyModule_AddIntConstant(m, "ST_MODE", 0)) return NULL;
568     if (PyModule_AddIntConstant(m, "ST_INO", 1)) return NULL;
569     if (PyModule_AddIntConstant(m, "ST_DEV", 2)) return NULL;
570     if (PyModule_AddIntConstant(m, "ST_NLINK", 3)) return NULL;
571     if (PyModule_AddIntConstant(m, "ST_UID", 4)) return NULL;
572     if (PyModule_AddIntConstant(m, "ST_GID", 5)) return NULL;
573     if (PyModule_AddIntConstant(m, "ST_SIZE", 6)) return NULL;
574     if (PyModule_AddIntConstant(m, "ST_ATIME", 7)) return NULL;
575     if (PyModule_AddIntConstant(m, "ST_MTIME", 8)) return NULL;
576     if (PyModule_AddIntConstant(m, "ST_CTIME", 9)) return NULL;
577 
578 #ifdef MS_WINDOWS
579     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_ARCHIVE)) return NULL;
580     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_COMPRESSED)) return NULL;
581     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_DEVICE)) return NULL;
582     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_DIRECTORY)) return NULL;
583     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_ENCRYPTED)) return NULL;
584     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_HIDDEN)) return NULL;
585     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_INTEGRITY_STREAM)) return NULL;
586     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_NORMAL)) return NULL;
587     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)) return NULL;
588     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_NO_SCRUB_DATA)) return NULL;
589     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_OFFLINE)) return NULL;
590     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_READONLY)) return NULL;
591     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_REPARSE_POINT)) return NULL;
592     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_SPARSE_FILE)) return NULL;
593     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_SYSTEM)) return NULL;
594     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_TEMPORARY)) return NULL;
595     if (PyModule_AddIntMacro(m, FILE_ATTRIBUTE_VIRTUAL)) return NULL;
596 
597     if (PyModule_AddObject(m, "IO_REPARSE_TAG_SYMLINK",
598         PyLong_FromUnsignedLong(IO_REPARSE_TAG_SYMLINK))) return NULL;
599     if (PyModule_AddObject(m, "IO_REPARSE_TAG_MOUNT_POINT",
600         PyLong_FromUnsignedLong(IO_REPARSE_TAG_MOUNT_POINT))) return NULL;
601     if (PyModule_AddObject(m, "IO_REPARSE_TAG_APPEXECLINK",
602         PyLong_FromUnsignedLong(IO_REPARSE_TAG_APPEXECLINK))) return NULL;
603 #endif
604 
605     return m;
606 }
607 
608 #ifdef __cplusplus
609 }
610 #endif
611