summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Doc/library/stat.rst51
-rw-r--r--Doc/whatsnew/3.4.rst7
-rw-r--r--Lib/stat.py6
-rw-r--r--Lib/test/test_stat.py57
-rw-r--r--Misc/NEWS2
-rw-r--r--Modules/Setup.dist1
-rw-r--r--Modules/_stat.c571
-rw-r--r--PC/VS9.0/pythoncore.vcproj4
-rw-r--r--PCbuild/pythoncore.vcxproj3
9 files changed, 679 insertions, 23 deletions
diff --git a/Doc/library/stat.rst b/Doc/library/stat.rst
index 02513df697..a021fe2e7e 100644
--- a/Doc/library/stat.rst
+++ b/Doc/library/stat.rst
@@ -6,7 +6,8 @@
os.lstat() and os.fstat().
.. sectionauthor:: Skip Montanaro <skip@automatrix.com>
-**Source code:** :source:`Lib/stat.py`
+**Source code:** :source:`Modules/_stat.c`
+ :source:`Lib/stat.py`
--------------
@@ -15,6 +16,9 @@ results of :func:`os.stat`, :func:`os.fstat` and :func:`os.lstat` (if they
exist). For complete details about the :c:func:`stat`, :c:func:`fstat` and
:c:func:`lstat` calls, consult the documentation for your system.
+.. versionchanged:: 3.4
+ The stat module is backed by a C implementation.
+
The :mod:`stat` module defines the following functions to test for specific file
types:
@@ -53,6 +57,24 @@ types:
Return non-zero if the mode is from a socket.
+.. function:: S_ISDOOR(mode)
+
+ Return non-zero if the mode is from a door.
+
+ .. versionadded:: 3.4
+
+.. function:: S_ISPORT(mode)
+
+ Return non-zero if the mode is from an event port.
+
+ .. versionadded:: 3.4
+
+.. function:: S_ISWHT(mode)
+
+ Return non-zero if the mode is from a whiteout.
+
+ .. versionadded:: 3.4
+
Two additional functions are defined for more general manipulation of the file's
mode:
@@ -113,6 +135,10 @@ readable string:
.. versionadded:: 3.3
+ .. versionchanged:: 3.4
+ The function supports :data:`S_IFDOOR`, :data:`S_IFPORT` and
+ :data:`S_IFWHT`.
+
All the variables below are simply symbolic indexes into the 10-tuple returned
by :func:`os.stat`, :func:`os.fstat` or :func:`os.lstat`.
@@ -210,6 +236,29 @@ Use of the functions above is more portable than use of the first set of flags:
FIFO.
+.. data:: S_IFDOOR
+
+ Door.
+
+ .. versionadded:: 3.4
+
+.. data:: S_IFPORT
+
+ Event port.
+
+ .. versionadded:: 3.4
+
+.. data:: S_IFWHT
+
+ Whiteout.
+
+ .. versionadded:: 3.4
+
+.. note::
+
+ :data:`S_IFDOOR`, :data:`S_IFPORT` or :data:`S_IFWHT` are defined as
+ 0 when the platform does not have support for the file types.
+
The following flags can also be used in the *mode* argument of :func:`os.chmod`:
.. data:: S_ISUID
diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst
index 16b03b336e..b003c4ea91 100644
--- a/Doc/whatsnew/3.4.rst
+++ b/Doc/whatsnew/3.4.rst
@@ -182,7 +182,6 @@ functools
New :func:`functools.singledispatch` decorator: see the :pep:`443`.
-
smtplib
-------
@@ -213,6 +212,12 @@ wave
The :meth:`~wave.getparams` method now returns a namedtuple rather than a
plain tuple. (Contributed by Claudiu Popa in :issue:`17487`.)
+stat
+---
+
+The stat module is now backed by a C implementation in :mod:`_stat`. A C
+implementation is required as most of the values aren't standardized and
+platform-dependent. (Contributed by Christian Heimes in :issue:`11016`.)
Optimizations
=============
diff --git a/Lib/stat.py b/Lib/stat.py
index 704adfe2e1..0ea653b014 100644
--- a/Lib/stat.py
+++ b/Lib/stat.py
@@ -147,3 +147,9 @@ def filemode(mode):
else:
perm.append("-")
return "".join(perm)
+
+# If available, use C implementation
+try:
+ from _stat import *
+except ModuleNotFoundError:
+ pass
diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py
index 8de5f360c4..735b2e61aa 100644
--- a/Lib/test/test_stat.py
+++ b/Lib/test/test_stat.py
@@ -1,9 +1,13 @@
import unittest
import os
from test.support import TESTFN, run_unittest, import_fresh_module
-import stat
+
+c_stat = import_fresh_module('stat', fresh=['_stat'])
+py_stat = import_fresh_module('stat', blocked=['_stat'])
class TestFilemode(unittest.TestCase):
+ statmod = None
+
file_flags = {'SF_APPEND', 'SF_ARCHIVED', 'SF_IMMUTABLE', 'SF_NOUNLINK',
'SF_SNAPSHOT', 'UF_APPEND', 'UF_COMPRESSED', 'UF_HIDDEN',
'UF_IMMUTABLE', 'UF_NODUMP', 'UF_NOUNLINK', 'UF_OPAQUE'}
@@ -60,17 +64,17 @@ class TestFilemode(unittest.TestCase):
def get_mode(self, fname=TESTFN):
st_mode = os.lstat(fname).st_mode
- modestr = stat.filemode(st_mode)
+ modestr = self.statmod.filemode(st_mode)
return st_mode, modestr
def assertS_IS(self, name, mode):
# test format, lstrip is for S_IFIFO
- fmt = getattr(stat, "S_IF" + name.lstrip("F"))
- self.assertEqual(stat.S_IFMT(mode), fmt)
+ fmt = getattr(self.statmod, "S_IF" + name.lstrip("F"))
+ self.assertEqual(self.statmod.S_IFMT(mode), fmt)
# test that just one function returns true
testname = "S_IS" + name
for funcname in self.format_funcs:
- func = getattr(stat, funcname, None)
+ func = getattr(self.statmod, funcname, None)
if func is None:
if funcname == testname:
raise ValueError(funcname)
@@ -88,35 +92,35 @@ class TestFilemode(unittest.TestCase):
st_mode, modestr = self.get_mode()
self.assertEqual(modestr, '-rwx------')
self.assertS_IS("REG", st_mode)
- self.assertEqual(stat.S_IMODE(st_mode),
- stat.S_IRWXU)
+ self.assertEqual(self.statmod.S_IMODE(st_mode),
+ self.statmod.S_IRWXU)
os.chmod(TESTFN, 0o070)
st_mode, modestr = self.get_mode()
self.assertEqual(modestr, '----rwx---')
self.assertS_IS("REG", st_mode)
- self.assertEqual(stat.S_IMODE(st_mode),
- stat.S_IRWXG)
+ self.assertEqual(self.statmod.S_IMODE(st_mode),
+ self.statmod.S_IRWXG)
os.chmod(TESTFN, 0o007)
st_mode, modestr = self.get_mode()
self.assertEqual(modestr, '-------rwx')
self.assertS_IS("REG", st_mode)
- self.assertEqual(stat.S_IMODE(st_mode),
- stat.S_IRWXO)
+ self.assertEqual(self.statmod.S_IMODE(st_mode),
+ self.statmod.S_IRWXO)
os.chmod(TESTFN, 0o444)
st_mode, modestr = self.get_mode()
self.assertS_IS("REG", st_mode)
self.assertEqual(modestr, '-r--r--r--')
- self.assertEqual(stat.S_IMODE(st_mode), 0o444)
+ self.assertEqual(self.statmod.S_IMODE(st_mode), 0o444)
else:
os.chmod(TESTFN, 0o700)
st_mode, modestr = self.get_mode()
self.assertEqual(modestr[:3], '-rw')
self.assertS_IS("REG", st_mode)
- self.assertEqual(stat.S_IFMT(st_mode),
- stat.S_IFREG)
+ self.assertEqual(self.statmod.S_IFMT(st_mode),
+ self.statmod.S_IFREG)
def test_directory(self):
os.mkdir(TESTFN)
@@ -162,25 +166,38 @@ class TestFilemode(unittest.TestCase):
def test_module_attributes(self):
for key, value in self.stat_struct.items():
- modvalue = getattr(stat, key)
+ modvalue = getattr(self.statmod, key)
self.assertEqual(value, modvalue, key)
for key, value in self.permission_bits.items():
- modvalue = getattr(stat, key)
+ modvalue = getattr(self.statmod, key)
self.assertEqual(value, modvalue, key)
for key in self.file_flags:
- modvalue = getattr(stat, key)
+ modvalue = getattr(self.statmod, key)
self.assertIsInstance(modvalue, int)
for key in self.formats:
- modvalue = getattr(stat, key)
+ modvalue = getattr(self.statmod, key)
self.assertIsInstance(modvalue, int)
for key in self.format_funcs:
- func = getattr(stat, key)
+ func = getattr(self.statmod, key)
self.assertTrue(callable(func))
self.assertEqual(func(0), 0)
+class TestFilemodeCStat(TestFilemode):
+ statmod = c_stat
+
+ formats = TestFilemode.formats | {'S_IFDOOR', 'S_IFPORT', 'S_IFWHT'}
+ format_funcss = TestFilemode.format_funcs | {'S_ISDOOR', 'S_ISPORT',
+ 'S_ISWHT'}
+
+
+class TestFilemodePyStat(TestFilemode):
+ statmod = py_stat
+
+
def test_main():
- run_unittest(TestFilemode)
+ run_unittest(TestFilemodeCStat)
+ run_unittest(TestFilemodePyStat)
if __name__ == '__main__':
test_main()
diff --git a/Misc/NEWS b/Misc/NEWS
index ecec86b4a5..7ef9154e63 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -123,6 +123,8 @@ Core and Builtins
Library
-------
+- Issue #11016: Add C implementation of the stat module as _stat.
+
- Issue #18248: Fix libffi build on AIX.
- Issue #18259: Declare sethostname in socketmodule.c for AIX
diff --git a/Modules/Setup.dist b/Modules/Setup.dist
index d4e1fe18d3..ebf8172df3 100644
--- a/Modules/Setup.dist
+++ b/Modules/Setup.dist
@@ -117,6 +117,7 @@ _operator _operator.c # operator.add() and similar goodies
_collections _collectionsmodule.c # Container types
itertools itertoolsmodule.c # Functions creating iterators for efficient looping
atexit atexitmodule.c # Register functions to be run at interpreter-shutdown
+_stat _stat.c # stat.h interface
# access to ISO C locale support
_locale _localemodule.c # -lintl
diff --git a/Modules/_stat.c b/Modules/_stat.c
new file mode 100644
index 0000000000..41a5a09d71
--- /dev/null
+++ b/Modules/_stat.c
@@ -0,0 +1,571 @@
+/* stat.h interface
+ *
+ * The module defines all S_IF*, S_I*, UF_*, SF_* and ST_* constants to
+ * sensible default values as well as defines S_IS*() macros in order to keep
+ * backward compatibility with the old stat.py module.
+ *
+ * New constants and macros such as S_IFDOOR / S_ISDOOR() are always defined
+ * as int 0.
+ *
+ * NOTE: POSIX only defines the values of the S_I* permission bits.
+ *
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include "Python.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+
+/* From Python's stat.py */
+#ifndef S_IMODE
+# define S_IMODE 07777
+#endif
+
+/* S_IFXXX constants (file types)
+ *
+ * Only the names are defined by POSIX but not their value. All common file
+ * types seems to have the same numeric value on all platforms, though.
+ */
+#ifndef S_IFMT
+# define S_IFMT 0170000
+#endif
+
+#ifndef S_IFDIR
+# define S_IFDIR 0040000
+#endif
+
+#ifndef S_IFCHR
+# define S_IFCHR 0020000
+#endif
+
+#ifndef S_IFBLK
+# define S_IFBLK 0060000
+#endif
+
+#ifndef S_IFREG
+# define S_IFREG 0100000
+#endif
+
+#ifndef S_IFIFO
+# define S_IFIFO 0010000
+#endif
+
+#ifndef S_IFLNK
+# define S_IFLNK 0120000
+#endif
+
+#ifndef S_IFSOCK
+# define S_IFSOCK 0140000
+#endif
+
+#ifndef S_IFDOOR
+# define S_IFDOOR 0
+#endif
+
+#ifndef S_IFPORT
+# define S_IFPORT 0
+#endif
+
+#ifndef S_IFWHT
+# define S_IFWHT 0
+#endif
+
+
+/* S_ISXXX() */
+#ifndef S_ISDIR
+# define S_ISDIR(mode) ((mode) & S_IFMT) == S_IDIR
+#endif
+
+#ifndef S_ISCHR
+# define S_ISCHR(mode) ((mode) & S_IFMT) == S_ICHR
+#endif
+
+#ifndef S_ISBLK
+# define S_ISBLK(mode) ((mode) & S_IFMT) == S_IBLK
+#endif
+
+#ifndef S_ISREG
+# define S_ISREG(mode) ((mode) & S_IFMT) == S_IREG
+#endif
+
+#ifndef S_ISFIFO
+# define S_ISFIFO(mode) ((mode) & S_IFMT) == S_IFIFO
+#endif
+
+#ifndef S_ISLNK
+# define S_ISLNK(mode) ((mode) & S_IFMT) == S_IFLNK
+#endif
+
+#ifndef S_ISSOCK
+# define S_ISSOCK(mode) ((mode) & S_IFMT) == S_IFSOCK
+#endif
+
+#ifndef S_ISDOOR
+# define S_ISDOOR(mode) 0
+#endif
+
+#ifndef S_ISPORT
+# define S_ISPORT(mode) 0
+#endif
+
+#ifndef S_ISWHT
+# define S_ISWHT(mode) 0
+#endif
+
+
+/* S_I* file permission
+ *
+ * The permission bit value are defined by POSIX standards.
+ */
+#ifndef S_ISUID
+# define S_ISUID 04000
+#endif
+
+#ifndef S_ISGID
+# define S_ISGID 02000
+#endif
+
+/* what is S_ENFMT? */
+#ifndef S_ENFMT
+# define S_ENFMT S_ISGID
+#endif
+
+#ifndef S_ISVTX
+# define S_ISVTX 01000
+#endif
+
+#ifndef S_IREAD
+# define S_IREAD 00400
+#endif
+
+#ifndef S_IWRITE
+# define S_IWRITE 00200
+#endif
+
+#ifndef S_IEXEC
+# define S_IEXEC 00100
+#endif
+
+#ifndef S_IRWXU
+# define S_IRWXU 00700
+#endif
+
+#ifndef S_IRUSR
+# define S_IRUSR 00400
+#endif
+
+#ifndef S_IWUSR
+# define S_IWUSR 00200
+#endif
+
+#ifndef S_IXUSR
+# define S_IXUSR 00100
+#endif
+
+#ifndef S_IRWXG
+# define S_IRWXG 00070
+#endif
+
+#ifndef S_IRGRP
+# define S_IRGRP 00040
+#endif
+
+#ifndef S_IWGRP
+# define S_IWGRP 00020
+#endif
+
+#ifndef S_IXGRP
+# define S_IXGRP 00010
+#endif
+
+#ifndef S_IRWXO
+# define S_IRWXO 00007
+#endif
+
+#ifndef S_IROTH
+# define S_IROTH 00004
+#endif
+
+#ifndef S_IWOTH
+# define S_IWOTH 00002
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 00001
+#endif
+
+
+/* Names for file flags */
+#ifndef UF_NODUMP
+# define UF_NODUMP 0x00000001
+#endif
+
+#ifndef UF_IMMUTABLE
+# define UF_IMMUTABLE 0x00000002
+#endif
+
+#ifndef UF_APPEND
+# define UF_APPEND 0x00000004
+#endif
+
+#ifndef UF_OPAQUE
+# define UF_OPAQUE 0x00000008
+#endif
+
+#ifndef UF_NOUNLINK
+# define UF_NOUNLINK 0x00000010
+#endif
+
+#ifndef UF_COMPRESSED
+# define UF_COMPRESSED 0x00000020
+#endif
+
+#ifndef UF_HIDDEN
+# define UF_HIDDEN 0x00008000
+#endif
+
+#ifndef SF_ARCHIVED
+# define SF_ARCHIVED 0x00010000
+#endif
+
+#ifndef SF_IMMUTABLE
+# define SF_IMMUTABLE 0x00020000
+#endif
+
+#ifndef SF_APPEND
+# define SF_APPEND 0x00040000
+#endif
+
+#ifndef SF_NOUNLINK
+# define SF_NOUNLINK 0x00100000
+#endif
+
+#ifndef SF_SNAPSHOT
+# define SF_SNAPSHOT 0x00200000
+#endif
+
+
+#define stat_S_ISFUNC(isfunc, doc) \
+ static PyObject * \
+ stat_ ##isfunc (PyObject *self, PyObject *omode) \
+ { \
+ unsigned long mode = PyLong_AsUnsignedLong(omode); \
+ if ((mode == (unsigned long)-1) && PyErr_Occurred()) { \
+ return NULL; \
+ } \
+ return PyBool_FromLong(isfunc(mode)); \
+ } \
+ PyDoc_STRVAR(stat_ ## isfunc ## _doc, doc)
+
+stat_S_ISFUNC(S_ISDIR,
+ "S_ISDIR(mode) -> bool\n\n"
+ "Return True if mode is from a directory.");
+
+stat_S_ISFUNC(S_ISCHR,
+ "S_ISCHR(mode) -> bool\n\n"
+ "Return True if mode is from a character special device file.");
+
+stat_S_ISFUNC(S_ISBLK,
+ "S_ISBLK(mode) -> bool\n\n"
+ "Return True if mode is from a block special device file.");
+
+stat_S_ISFUNC(S_ISREG,
+ "S_ISREG(mode) -> bool\n\n"
+ "Return True if mode is from a regular file.");
+
+stat_S_ISFUNC(S_ISFIFO,
+ "S_ISFIFO(mode) -> bool\n\n"
+ "Return True if mode is from a FIFO (named pipe).");
+
+stat_S_ISFUNC(S_ISLNK,
+ "S_ISLNK(mode) -> bool\n\n"
+ "Return True if mode is from a symbolic link.");
+
+stat_S_ISFUNC(S_ISSOCK,
+ "S_ISSOCK(mode) -> bool\n\n"
+ "Return True if mode is from a socket.");
+
+stat_S_ISFUNC(S_ISDOOR,
+ "S_ISDOOR(mode) -> bool\n\n"
+ "Return True if mode is from a door.");
+
+stat_S_ISFUNC(S_ISPORT,
+ "S_ISPORT(mode) -> bool\n\n"
+ "Return True if mode is from an event port.");
+
+stat_S_ISFUNC(S_ISWHT,
+ "S_ISWHT(mode) -> bool\n\n"
+ "Return True if mode is from a whiteout.");
+
+
+PyDoc_STRVAR(stat_S_IMODE_doc,
+"Return the portion of the file's mode that can be set by os.chmod().");
+
+static PyObject *
+stat_S_IMODE(PyObject *self, PyObject *omode)
+{
+ unsigned long mode = PyLong_AsUnsignedLong(omode);
+ if ((mode == (unsigned long)-1) && PyErr_Occurred()) {
+ return NULL;
+ }
+ return PyLong_FromUnsignedLong(mode & S_IMODE);
+}
+
+
+PyDoc_STRVAR(stat_S_IFMT_doc,
+"Return the portion of the file's mode that describes the file type.");
+
+static PyObject *
+stat_S_IFMT(PyObject *self, PyObject *omode)
+{
+ unsigned long mode = PyLong_AsUnsignedLong(omode);
+ if ((mode == (unsigned long)-1) && PyErr_Occurred()) {
+ return NULL;
+ }
+ return PyLong_FromUnsignedLong(mode & S_IFMT);
+}
+
+/* file type chars according to
+ http://en.wikibooks.org/wiki/C_Programming/POSIX_Reference/sys/stat.h */
+
+static char
+filetype(mode_t mode)
+{
+ /* common cases first */
+ if (S_ISREG(mode)) return '-';
+ if (S_ISDIR(mode)) return 'd';
+ if (S_ISLNK(mode)) return 'l';
+ /* special files */
+ if (S_ISBLK(mode)) return 'b';
+ if (S_ISCHR(mode)) return 'c';
+ if (S_ISFIFO(mode)) return 'p';
+ if (S_ISSOCK(mode)) return 's';
+ /* non-standard types */
+ if (S_ISDOOR(mode)) return 'D';
+ if (S_ISPORT(mode)) return 'P';
+ if (S_ISWHT(mode)) return 'w';
+ /* unknown */
+ return '?';
+}
+
+static void
+fileperm(mode_t mode, char *buf)
+{
+ buf[0] = mode & S_IRUSR ? 'r' : '-';
+ buf[1] = mode & S_IWUSR ? 'w' : '-';
+ if (mode & S_ISUID) {
+ buf[2] = mode & S_IXUSR ? 's' : 'S';
+ } else {
+ buf[2] = mode & S_IXUSR ? 'x' : '-';
+ }
+ buf[3] = mode & S_IRGRP ? 'r' : '-';
+ buf[4] = mode & S_IWGRP ? 'w' : '-';
+ if (mode & S_ISGID) {
+ buf[5] = mode & S_IXGRP ? 's' : 'S';
+ } else {
+ buf[5] = mode & S_IXGRP ? 'x' : '-';
+ }
+ buf[6] = mode & S_IROTH ? 'r' : '-';
+ buf[7] = mode & S_IWOTH ? 'w' : '-';
+ if (mode & S_ISVTX) {
+ buf[8] = mode & S_IXOTH ? 't' : 'T';
+ } else {
+ buf[8] = mode & S_IXOTH ? 'x' : '-';
+ }
+}
+
+PyDoc_STRVAR(stat_filemode_doc,
+"Convert a file's mode to a string of the form '-rwxrwxrwx'");
+
+static PyObject *
+stat_filemode(PyObject *self, PyObject *omode)
+{
+ char buf[10];
+ unsigned long mode;
+
+ mode = PyLong_AsUnsignedLong(omode);
+ if ((mode == (unsigned long)-1) && PyErr_Occurred()) {
+ return NULL;
+ }
+
+ buf[0] = filetype(mode);
+ fileperm(mode, &buf[1]);
+ return PyUnicode_FromStringAndSize(buf, 10);
+}
+
+
+static PyMethodDef stat_methods[] = {
+ {"S_ISDIR", stat_S_ISDIR, METH_O, stat_S_ISDIR_doc},
+ {"S_ISCHR", stat_S_ISCHR, METH_O, stat_S_ISCHR_doc},
+ {"S_ISBLK", stat_S_ISBLK, METH_O, stat_S_ISBLK_doc},
+ {"S_ISREG", stat_S_ISREG, METH_O, stat_S_ISREG_doc},
+ {"S_ISFIFO", stat_S_ISFIFO, METH_O, stat_S_ISFIFO_doc},
+ {"S_ISLNK", stat_S_ISLNK, METH_O, stat_S_ISLNK_doc},
+ {"S_ISSOCK", stat_S_ISSOCK, METH_O, stat_S_ISSOCK_doc},
+ {"S_ISDOOR", stat_S_ISDOOR, METH_O, stat_S_ISDOOR_doc},
+ {"S_ISPORT", stat_S_ISPORT, METH_O, stat_S_ISPORT_doc},
+ {"S_ISWHT", stat_S_ISWHT, METH_O, stat_S_ISWHT_doc},
+ {"S_IMODE", stat_S_IMODE, METH_O, stat_S_IMODE_doc},
+ {"S_IFMT", stat_S_IFMT, METH_O, stat_S_IFMT_doc},
+ {"filemode", stat_filemode, METH_O, stat_filemode_doc},
+ {NULL, NULL} /* sentinel */
+};
+
+
+PyDoc_STRVAR(module_doc,
+"S_IFMT_: file type bits\n\
+S_IFDIR: directory\n\
+S_IFCHR: character device\n\
+S_IFBLK: block device\n\
+S_IFREG: regular file\n\
+S_IFIFO: fifo (named pipe)\n\
+S_IFLNK: symbolic link\n\
+S_IFSOCK: socket file\n\
+S_IFDOOR: door\n\
+S_IFPORT: event port\n\
+S_IFWHT: whiteout\n\
+\n"
+
+"S_ISUID: set UID bit\n\
+S_ISGID: set GID bit\n\
+S_ENFMT: file locking enforcement\n\
+S_ISVTX: sticky bit\n\
+S_IREAD: Unix V7 synonym for S_IRUSR\n\
+S_IWRITE: Unix V7 synonym for S_IWUSR\n\
+S_IEXEC: Unix V7 synonym for S_IXUSR\n\
+S_IRWXU: mask for owner permissions\n\
+S_IRUSR: read by owner\n\
+S_IWUSR: write by owner\n\
+S_IXUSR: execute by owner\n\
+S_IRWXG: mask for group permissions\n\
+S_IRGRP: read by group\n\
+S_IWGRP: write by group\n\
+S_IXGRP: execute by group\n\
+S_IRWXO: mask for others (not in group) permissions\n\
+S_IROTH: read by others\n\
+S_IWOTH: write by others\n\
+S_IXOTH: execute by others\n\
+\n"
+
+"UF_NODUMP: do not dump file\n\
+UF_IMMUTABLE: file may not be changed\n\
+UF_APPEND: file may only be appended to\n\
+UF_OPAQUE: directory is opaque when viewed through a union stack\n\
+UF_NOUNLINK: file may not be renamed or deleted\n\
+UF_COMPRESSED: OS X: file is hfs-compressed\n\
+UF_HIDDEN: OS X: file should not be displayed\n\
+SF_ARCHIVED: file may be archived\n\
+SF_IMMUTABLE: file may not be changed\n\
+SF_APPEND: file may only be appended to\n\
+SF_NOUNLINK: file may not be renamed or deleted\n\
+SF_SNAPSHOT: file is a snapshot file\n\
+\n"
+
+"ST_MODE\n\
+ST_INO\n\
+ST_DEV\n\
+ST_NLINK\n\
+ST_UID\n\
+ST_GID\n\
+ST_SIZE\n\
+ST_ATIME\n\
+ST_MTIME\n\
+ST_CTIME\n\
+");
+
+
+static struct PyModuleDef statmodule = {
+ PyModuleDef_HEAD_INIT,
+ "_stat",
+ module_doc,
+ -1,
+ stat_methods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+PyMODINIT_FUNC
+PyInit__stat(void)
+{
+ PyObject *m;
+ m = PyModule_Create(&statmodule);
+ if (m == NULL)
+ return NULL;
+
+ if (PyModule_AddIntMacro(m, S_IFDIR)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IFCHR)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IFBLK)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IFREG)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IFIFO)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IFLNK)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IFSOCK)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IFDOOR)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IFPORT)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IFWHT)) return NULL;
+
+ if (PyModule_AddIntMacro(m, S_ISUID)) return NULL;
+ if (PyModule_AddIntMacro(m, S_ISGID)) return NULL;
+ if (PyModule_AddIntMacro(m, S_ISVTX)) return NULL;
+ if (PyModule_AddIntMacro(m, S_ENFMT)) return NULL;
+
+ if (PyModule_AddIntMacro(m, S_IREAD)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IWRITE)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IEXEC)) return NULL;
+
+ if (PyModule_AddIntMacro(m, S_IRWXU)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IRUSR)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IWUSR)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IXUSR)) return NULL;
+
+ if (PyModule_AddIntMacro(m, S_IRWXG)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IRGRP)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IWGRP)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IXGRP)) return NULL;
+
+ if (PyModule_AddIntMacro(m, S_IRWXO)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IROTH)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IWOTH)) return NULL;
+ if (PyModule_AddIntMacro(m, S_IXOTH)) return NULL;
+
+ if (PyModule_AddIntMacro(m, UF_NODUMP)) return NULL;
+ if (PyModule_AddIntMacro(m, UF_IMMUTABLE)) return NULL;
+ if (PyModule_AddIntMacro(m, UF_APPEND)) return NULL;
+ if (PyModule_AddIntMacro(m, UF_OPAQUE)) return NULL;
+ if (PyModule_AddIntMacro(m, UF_NOUNLINK)) return NULL;
+ if (PyModule_AddIntMacro(m, UF_COMPRESSED)) return NULL;
+ if (PyModule_AddIntMacro(m, UF_HIDDEN)) return NULL;
+ if (PyModule_AddIntMacro(m, SF_ARCHIVED)) return NULL;
+ if (PyModule_AddIntMacro(m, SF_IMMUTABLE)) return NULL;
+ if (PyModule_AddIntMacro(m, SF_APPEND)) return NULL;
+ if (PyModule_AddIntMacro(m, SF_NOUNLINK)) return NULL;
+ if (PyModule_AddIntMacro(m, SF_SNAPSHOT)) return NULL;
+
+ if (PyModule_AddIntConstant(m, "ST_MODE", 0)) return NULL;
+ if (PyModule_AddIntConstant(m, "ST_INO", 1)) return NULL;
+ if (PyModule_AddIntConstant(m, "ST_DEV", 2)) return NULL;
+ if (PyModule_AddIntConstant(m, "ST_NLINK", 3)) return NULL;
+ if (PyModule_AddIntConstant(m, "ST_UID", 4)) return NULL;
+ if (PyModule_AddIntConstant(m, "ST_GID", 5)) return NULL;
+ if (PyModule_AddIntConstant(m, "ST_SIZE", 6)) return NULL;
+ if (PyModule_AddIntConstant(m, "ST_ATIME", 7)) return NULL;
+ if (PyModule_AddIntConstant(m, "ST_MTIME", 8)) return NULL;
+ if (PyModule_AddIntConstant(m, "ST_CTIME", 9)) return NULL;
+
+ return m;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/PC/VS9.0/pythoncore.vcproj b/PC/VS9.0/pythoncore.vcproj
index c5ee9a69d0..6524c922f8 100644
--- a/PC/VS9.0/pythoncore.vcproj
+++ b/PC/VS9.0/pythoncore.vcproj
@@ -1155,6 +1155,10 @@
>
</File>
<File
+ RelativePath="..\..\Modules\_stat.c"
+ >
+ </File>
+ <File
RelativePath="..\..\Modules\symtablemodule.c"
>
</File>
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index bba98bb258..5768b36864 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -525,6 +525,7 @@
<ClCompile Include="..\Modules\sha256module.c" />
<ClCompile Include="..\Modules\sha512module.c" />
<ClCompile Include="..\Modules\signalmodule.c" />
+ <ClCompile Include="..\Modules\_stat.c" />
<ClCompile Include="..\Modules\symtablemodule.c" />
<ClCompile Include="..\Modules\_threadmodule.c" />
<ClCompile Include="..\Modules\timemodule.c" />
@@ -678,4 +679,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project> \ No newline at end of file
+</Project>