Author: Armin Rigo <ar...@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) +@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) + +@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') _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit