xref: /third_party/python/Modules/_stat.c (revision 7db96d56)
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
18extern "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>
31typedef 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
251static 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
281stat_S_ISFUNC(S_ISDIR,
282    "S_ISDIR(mode) -> bool\n\n"
283    "Return True if mode is from a directory.");
284
285stat_S_ISFUNC(S_ISCHR,
286    "S_ISCHR(mode) -> bool\n\n"
287    "Return True if mode is from a character special device file.");
288
289stat_S_ISFUNC(S_ISBLK,
290    "S_ISBLK(mode) -> bool\n\n"
291    "Return True if mode is from a block special device file.");
292
293stat_S_ISFUNC(S_ISREG,
294    "S_ISREG(mode) -> bool\n\n"
295    "Return True if mode is from a regular file.");
296
297stat_S_ISFUNC(S_ISFIFO,
298    "S_ISFIFO(mode) -> bool\n\n"
299    "Return True if mode is from a FIFO (named pipe).");
300
301stat_S_ISFUNC(S_ISLNK,
302    "S_ISLNK(mode) -> bool\n\n"
303    "Return True if mode is from a symbolic link.");
304
305stat_S_ISFUNC(S_ISSOCK,
306    "S_ISSOCK(mode) -> bool\n\n"
307    "Return True if mode is from a socket.");
308
309stat_S_ISFUNC(S_ISDOOR,
310    "S_ISDOOR(mode) -> bool\n\n"
311    "Return True if mode is from a door.");
312
313stat_S_ISFUNC(S_ISPORT,
314    "S_ISPORT(mode) -> bool\n\n"
315    "Return True if mode is from an event port.");
316
317stat_S_ISFUNC(S_ISWHT,
318    "S_ISWHT(mode) -> bool\n\n"
319    "Return True if mode is from a whiteout.");
320
321
322PyDoc_STRVAR(stat_S_IMODE_doc,
323"Return the portion of the file's mode that can be set by os.chmod().");
324
325static PyObject *
326stat_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
335PyDoc_STRVAR(stat_S_IFMT_doc,
336"Return the portion of the file's mode that describes the file type.");
337
338static PyObject *
339stat_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
350static char
351filetype(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
370static void
371fileperm(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
396PyDoc_STRVAR(stat_filemode_doc,
397"Convert a file's mode to a string of the form '-rwxrwxrwx'");
398
399static PyObject *
400stat_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
415static 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
433PyDoc_STRVAR(module_doc,
434"S_IFMT_: file type bits\n\
435S_IFDIR: directory\n\
436S_IFCHR: character device\n\
437S_IFBLK: block device\n\
438S_IFREG: regular file\n\
439S_IFIFO: fifo (named pipe)\n\
440S_IFLNK: symbolic link\n\
441S_IFSOCK: socket file\n\
442S_IFDOOR: door\n\
443S_IFPORT: event port\n\
444S_IFWHT: whiteout\n\
445\n"
446
447"S_ISUID: set UID bit\n\
448S_ISGID: set GID bit\n\
449S_ENFMT: file locking enforcement\n\
450S_ISVTX: sticky bit\n\
451S_IREAD: Unix V7 synonym for S_IRUSR\n\
452S_IWRITE: Unix V7 synonym for S_IWUSR\n\
453S_IEXEC: Unix V7 synonym for S_IXUSR\n\
454S_IRWXU: mask for owner permissions\n\
455S_IRUSR: read by owner\n\
456S_IWUSR: write by owner\n\
457S_IXUSR: execute by owner\n\
458S_IRWXG: mask for group permissions\n\
459S_IRGRP: read by group\n\
460S_IWGRP: write by group\n\
461S_IXGRP: execute by group\n\
462S_IRWXO: mask for others (not in group) permissions\n\
463S_IROTH: read by others\n\
464S_IWOTH: write by others\n\
465S_IXOTH: execute by others\n\
466\n"
467
468"UF_NODUMP: do not dump file\n\
469UF_IMMUTABLE: file may not be changed\n\
470UF_APPEND: file may only be appended to\n\
471UF_OPAQUE: directory is opaque when viewed through a union stack\n\
472UF_NOUNLINK: file may not be renamed or deleted\n\
473UF_COMPRESSED: OS X: file is hfs-compressed\n\
474UF_HIDDEN: OS X: file should not be displayed\n\
475SF_ARCHIVED: file may be archived\n\
476SF_IMMUTABLE: file may not be changed\n\
477SF_APPEND: file may only be appended to\n\
478SF_NOUNLINK: file may not be renamed or deleted\n\
479SF_SNAPSHOT: file is a snapshot file\n\
480\n"
481
482"ST_MODE\n\
483ST_INO\n\
484ST_DEV\n\
485ST_NLINK\n\
486ST_UID\n\
487ST_GID\n\
488ST_SIZE\n\
489ST_ATIME\n\
490ST_MTIME\n\
491ST_CTIME\n\
492\n"
493
494"FILE_ATTRIBUTE_*: Windows file attribute constants\n\
495                   (only present on Windows)\n\
496");
497
498
499static int
500stat_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
613static PyModuleDef_Slot stat_slots[] = {
614    {Py_mod_exec, stat_exec},
615    {0, NULL}
616};
617
618
619static 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
629PyMODINIT_FUNC
630PyInit__stat(void)
631{
632    return PyModuleDef_Init(&statmodule);
633}
634
635#ifdef __cplusplus
636}
637#endif
638