[pypy-commit] pypy default: Support for the Python3 version of os.stat()

arigo pypy.commits at gmail.com
Sun Jun 11 17:22:41 EDT 2017


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r91577:6f7b1081c651
Date: 2017-06-11 23:11 +0200
http://bitbucket.org/pypy/pypy/changeset/6f7b1081c651/

Log:	Support for the Python3 version of os.stat()

diff --git a/rpython/rlib/rposix_stat.py b/rpython/rlib/rposix_stat.py
--- a/rpython/rlib/rposix_stat.py
+++ b/rpython/rlib/rposix_stat.py
@@ -600,6 +600,28 @@
         path = traits.as_str0(path)
         return win32_xstat(traits, path, traverse=False)
 
+ at specialize.argtype(0)
+def stat3(path):
+    # On Windows, the algorithm behind os.stat() changed a lot between
+    # Python 2 and Python 3.  This is the Python 3 version.
+    if not _WIN32:
+        return stat(path)
+    else:
+        traits = _preferred_traits(path)
+        path = traits.as_str0(path)
+        return win32_xstat3(traits, path, traverse=True)
+
+ at specialize.argtype(0)
+def lstat3(path):
+    # On Windows, the algorithm behind os.lstat() changed a lot between
+    # Python 2 and Python 3.  This is the Python 3 version.
+    if not _WIN32:
+        return lstat(path)
+    else:
+        traits = _preferred_traits(path)
+        path = traits.as_str0(path)
+        return win32_xstat3(traits, path, traverse=False)
+
 if rposix.HAVE_FSTATAT:
     from rpython.rlib.rposix import AT_FDCWD, AT_SYMLINK_NOFOLLOW
     c_fstatat = rffi.llexternal('fstatat64' if _LINUX else 'fstatat',
@@ -658,6 +680,45 @@
             return win32_attribute_data_to_stat(win32traits, data)
 
     @specialize.arg(0)
+    def win32_xstat3(traits, path, traverse=False):
+        # This is the Python3 version of os.stat() or lstat().
+        # XXX 'traverse' is ignored, and everything related to
+        # the "reparse points" is missing
+        win32traits = make_win32_traits(traits)
+
+        hFile = win32traits.CreateFile(path,
+            win32traits.FILE_READ_ATTRIBUTES,
+            0,
+            lltype.nullptr(rwin32.LPSECURITY_ATTRIBUTES.TO),
+            win32traits.OPEN_EXISTING,
+            win32traits.FILE_ATTRIBUTE_NORMAL |
+                win32traits.FILE_FLAG_BACKUP_SEMANTICS |
+                0,  # win32traits.FILE_FLAG_OPEN_REPARSE_POINT,
+            rwin32.NULL_HANDLE)
+
+        if hFile == rwin32.INVALID_HANDLE_VALUE:
+            errcode = rwin32.GetLastError_saved()
+            if (errcode != win32traits.ERROR_ACCESS_DENIED and
+                errcode != win32traits.ERROR_SHARING_VIOLATION):
+                raise WindowsError(errcode, "os_stat failed")
+
+            with lltype.scoped_alloc(
+                    win32traits.WIN32_FILE_ATTRIBUTE_DATA) as data:
+                if win32_attributes_from_dir(win32traits, path, data) == 0:
+                    raise WindowsError(rwin32.GetLastError_saved(),
+                                       "win32_attributes_from_dir failed")
+                return win32_attribute_data_to_stat(win32traits, data)
+
+        with lltype.scoped_alloc(
+                win32traits.BY_HANDLE_FILE_INFORMATION) as data:
+            res = rwin32.GetFileInformationByHandle(hFile, data)
+            errcode = rwin32.GetLastError_saved()
+            win32.CloseHandle(hFile)
+            if res == 0:
+                raise WindowsError(errcode, "GetFileInformationByHandle failed")
+            return win32_by_handle_info_to_stat(win32traits, data)
+
+    @specialize.arg(0)
     def win32_attributes_to_mode(win32traits, attributes):
         m = 0
         attributes = intmask(attributes)
@@ -697,10 +758,11 @@
 
         # specific to fstat()
         st_ino = make_longlong(info.c_nFileIndexHigh, info.c_nFileIndexLow)
+        st_dev = info.c_dwVolumeSerialNumber
         st_nlink = info.c_nNumberOfLinks
 
         result = (st_mode,
-                  st_ino, 0, st_nlink, 0, 0,
+                  st_ino, st_dev, st_nlink, 0, 0,
                   st_size,
                   atime, mtime, ctime,
                   extra_atime, extra_mtime, extra_ctime)
@@ -724,4 +786,3 @@
             return 1
         finally:
             lltype.free(filedata, flavor='raw')
-
diff --git a/rpython/rlib/rwin32file.py b/rpython/rlib/rwin32file.py
--- a/rpython/rlib/rwin32file.py
+++ b/rpython/rlib/rwin32file.py
@@ -46,6 +46,8 @@
             'INVALID_FILE_ATTRIBUTES')
         ERROR_SHARING_VIOLATION = platform.ConstantInteger(
             'ERROR_SHARING_VIOLATION')
+        ERROR_ACCESS_DENIED = platform.ConstantInteger(
+            'ERROR_ACCESS_DENIED')
         MOVEFILE_REPLACE_EXISTING = platform.ConstantInteger(
             'MOVEFILE_REPLACE_EXISTING')
         _S_IFDIR = platform.ConstantInteger('_S_IFDIR')
@@ -56,10 +58,14 @@
         FILE_TYPE_CHAR = platform.ConstantInteger('FILE_TYPE_CHAR')
         FILE_TYPE_PIPE = platform.ConstantInteger('FILE_TYPE_PIPE')
 
+        FILE_READ_ATTRIBUTES = platform.ConstantInteger(
+            'FILE_READ_ATTRIBUTES')
         FILE_WRITE_ATTRIBUTES = platform.ConstantInteger(
             'FILE_WRITE_ATTRIBUTES')
         OPEN_EXISTING = platform.ConstantInteger(
             'OPEN_EXISTING')
+        FILE_ATTRIBUTE_NORMAL = platform.ConstantInteger(
+            'FILE_ATTRIBUTE_NORMAL')
         FILE_FLAG_BACKUP_SEMANTICS = platform.ConstantInteger(
             'FILE_FLAG_BACKUP_SEMANTICS')
         VOLUME_NAME_DOS = platform.ConstantInteger('VOLUME_NAME_DOS')
@@ -103,10 +109,12 @@
                        INVALID_FILE_ATTRIBUTES
                        _S_IFDIR _S_IFREG _S_IFCHR _S_IFIFO
                        FILE_TYPE_UNKNOWN FILE_TYPE_CHAR FILE_TYPE_PIPE
+                       FILE_READ_ATTRIBUTES
                        FILE_WRITE_ATTRIBUTES OPEN_EXISTING FILE_FLAG_BACKUP_SEMANTICS
                        VOLUME_NAME_DOS VOLUME_NAME_NT
                        ERROR_FILE_NOT_FOUND ERROR_NO_MORE_FILES
                        ERROR_SHARING_VIOLATION MOVEFILE_REPLACE_EXISTING
+                       ERROR_ACCESS_DENIED
                     '''.split():
             locals()[name] = config[name]
         LPWIN32_FIND_DATA    = lltype.Ptr(WIN32_FIND_DATA)
diff --git a/rpython/rlib/test/test_rposix_stat.py b/rpython/rlib/test/test_rposix_stat.py
--- a/rpython/rlib/test/test_rposix_stat.py
+++ b/rpython/rlib/test/test_rposix_stat.py
@@ -68,6 +68,16 @@
             py.test.skip("the underlying os.fstatvfs() failed: %s" % e)
         rposix_stat.fstatvfs(0)
 
+    @py.test.mark.skipif(sys.platform != 'win32', reason='win32 test')
+    def test_stat3_ino_dev(self):
+        st = rposix.stat2('C:\\')
+        assert st.st_dev == st.st_ino == 0
+        st = rposix.stat3('C:\\')
+        assert st.st_dev != 0 and st.st_ino != 0
+        st2 = rposix.lstat3('C:\\')
+        assert (st2.st_dev, st2.st_ino) == (st.st_dev, st.st_ino)
+
+
 @py.test.mark.skipif("not hasattr(rposix_stat, 'fstatat')")
 def test_fstatat(tmpdir):
     tmpdir.join('file').write('text')


More information about the pypy-commit mailing list