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