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 int
stat_exec(PyObject * module)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_AddObject(module, "IO_REPARSE_TAG_SYMLINK",
596 PyLong_FromUnsignedLong(IO_REPARSE_TAG_SYMLINK)) < 0) {
597 return -1;
598 }
599 if (PyModule_AddObject(module, "IO_REPARSE_TAG_MOUNT_POINT",
600 PyLong_FromUnsignedLong(IO_REPARSE_TAG_MOUNT_POINT)) < 0) {
601 return -1;
602 }
603 if (PyModule_AddObject(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 {0, NULL}
616 };
617
618
619 static struct PyModuleDef statmodule = {
620 PyModuleDef_HEAD_INIT,
621 .m_name = "_stat",
622 .m_doc = module_doc,
623 .m_size = 0,
624 .m_methods = stat_methods,
625 .m_slots = stat_slots,
626 };
627
628
629 PyMODINIT_FUNC
PyInit__stat(void)630 PyInit__stat(void)
631 {
632 return PyModuleDef_Init(&statmodule);
633 }
634
635 #ifdef __cplusplus
636 }
637 #endif
638