def make_traits(traits): win32traits = make_win32_traits(traits) class NTTraits(win32traits): GetFinalPathNameByHandle_HANDLE = lltype.nullptr(rffi.VOIDP.TO) def check_GetFinalPathNameByHandle(self): if (self.GetFinalPathNameByHandle_HANDLE != lltype.nullptr(rffi.VOIDP.TO)): return True from rpython.rlib.rdynload import GetModuleHandle, dlsym hKernel32 = GetModuleHandle("KERNEL32") try: func = dlsym(hKernel32, 'GetFinalPathNameByHandleW') except KeyError: return False self.GetFinalPathNameByHandle_HANDLE = func return True def GetFinalPathNameByHandle(self, *args): assert (self.GetFinalPathNameByHandle_HANDLE != lltype.nullptr(rffi.VOIDP.TO)) return pypy_GetFinalPathNameByHandle( self.GetFinalPathNameByHandle_HANDLE, *args) return NTTraits()
def make_win32_stat_impl(name, traits): from rpython.rlib import rwin32 from rpython.rtyper.module.ll_win32file import make_win32_traits win32traits = make_win32_traits(traits) # The CRT of Windows has a number of flaws wrt. its stat() implementation: # - time stamps are restricted to second resolution # - file modification times suffer from forth-and-back conversions between # UTC and local time # Therefore, we implement our own stat, based on the Win32 API directly. from rpython.rtyper.tool import rffi_platform as platform from rpython.translator.tool.cbuild import ExternalCompilationInfo from rpython.rlib import rwin32 assert len(STAT_FIELDS) == 10 # no extra fields on Windows def attributes_to_mode(attributes): m = 0 attributes = intmask(attributes) if attributes & win32traits.FILE_ATTRIBUTE_DIRECTORY: m |= win32traits._S_IFDIR | 0111 # IFEXEC for user,group,other else: m |= win32traits._S_IFREG if attributes & win32traits.FILE_ATTRIBUTE_READONLY: m |= 0444 else: m |= 0666 return m def attribute_data_to_stat(info): st_mode = attributes_to_mode(info.c_dwFileAttributes) st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow) ctime, ctime_ns = FILE_TIME_to_time_t_nsec(info.c_ftCreationTime) mtime, mtime_ns = FILE_TIME_to_time_t_nsec(info.c_ftLastWriteTime) atime, atime_ns = FILE_TIME_to_time_t_nsec(info.c_ftLastAccessTime) result = (st_mode, 0, 0, 0, 0, 0, st_size, float(atime) + atime_ns * 1e-9, float(mtime) + mtime_ns * 1e-9, float(ctime) + ctime_ns * 1e-9) return make_stat_result(result) def by_handle_info_to_stat(info): # similar to the one above st_mode = attributes_to_mode(info.c_dwFileAttributes) st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow) ctime, ctime_ns = FILE_TIME_to_time_t_nsec(info.c_ftCreationTime) mtime, mtime_ns = FILE_TIME_to_time_t_nsec(info.c_ftLastWriteTime) atime, atime_ns = FILE_TIME_to_time_t_nsec(info.c_ftLastAccessTime) # specific to fstat() st_ino = make_longlong(info.c_nFileIndexHigh, info.c_nFileIndexLow) st_nlink = info.c_nNumberOfLinks result = (st_mode, st_ino, 0, st_nlink, 0, 0, st_size, atime + atime_ns * 1e-9, mtime + mtime_ns * 1e-9, ctime + ctime_ns * 1e-9) return make_stat_result(result) def attributes_from_dir(l_path, data): filedata = lltype.malloc(win32traits.WIN32_FIND_DATA, flavor='raw') try: hFindFile = win32traits.FindFirstFile(l_path, filedata) if hFindFile == rwin32.INVALID_HANDLE_VALUE: return 0 win32traits.FindClose(hFindFile) data.c_dwFileAttributes = filedata.c_dwFileAttributes rffi.structcopy(data.c_ftCreationTime, filedata.c_ftCreationTime) rffi.structcopy(data.c_ftLastAccessTime, filedata.c_ftLastAccessTime) rffi.structcopy(data.c_ftLastWriteTime, filedata.c_ftLastWriteTime) data.c_nFileSizeHigh = filedata.c_nFileSizeHigh data.c_nFileSizeLow = filedata.c_nFileSizeLow return 1 finally: lltype.free(filedata, flavor='raw') def win32_stat_llimpl(path): data = lltype.malloc(win32traits.WIN32_FILE_ATTRIBUTE_DATA, flavor='raw') try: l_path = traits.str2charp(path) res = win32traits.GetFileAttributesEx(l_path, win32traits.GetFileExInfoStandard, data) errcode = rwin32.GetLastError() if res == 0: if errcode == win32traits.ERROR_SHARING_VIOLATION: res = attributes_from_dir(l_path, data) errcode = rwin32.GetLastError() traits.free_charp(l_path) if res == 0: raise WindowsError(errcode, "os_stat failed") return attribute_data_to_stat(data) finally: lltype.free(data, flavor='raw') def win32_fstat_llimpl(fd): handle = rwin32.get_osfhandle(fd) filetype = win32traits.GetFileType(handle) if filetype == win32traits.FILE_TYPE_CHAR: # console or LPT device return make_stat_result((win32traits._S_IFCHR, 0, 0, 0, 0, 0, 0, 0, 0, 0)) elif filetype == win32traits.FILE_TYPE_PIPE: # socket or named pipe return make_stat_result((win32traits._S_IFIFO, 0, 0, 0, 0, 0, 0, 0, 0, 0)) elif filetype == win32traits.FILE_TYPE_UNKNOWN: error = rwin32.GetLastError() if error != 0: raise WindowsError(error, "os_fstat failed") # else: unknown but valid file # normal disk file (FILE_TYPE_DISK) info = lltype.malloc(win32traits.BY_HANDLE_FILE_INFORMATION, flavor='raw', zero=True) try: res = win32traits.GetFileInformationByHandle(handle, info) if res == 0: raise WindowsError(rwin32.GetLastError(), "os_fstat failed") return by_handle_info_to_stat(info) finally: lltype.free(info, flavor='raw') if name == 'fstat': return win32_fstat_llimpl else: return win32_stat_llimpl
def make_win32_stat_impl(name, traits): from rpython.rlib import rwin32 from rpython.rtyper.module.ll_win32file import make_win32_traits win32traits = make_win32_traits(traits) # The CRT of Windows has a number of flaws wrt. its stat() implementation: # - time stamps are restricted to second resolution # - file modification times suffer from forth-and-back conversions between # UTC and local time # Therefore, we implement our own stat, based on the Win32 API directly. from rpython.rtyper.tool import rffi_platform as platform from rpython.translator.tool.cbuild import ExternalCompilationInfo from rpython.rlib import rwin32 assert len(STAT_FIELDS) == 10 # no extra fields on Windows def attributes_to_mode(attributes): m = 0 attributes = intmask(attributes) if attributes & win32traits.FILE_ATTRIBUTE_DIRECTORY: m |= win32traits._S_IFDIR | 0111 # IFEXEC for user,group,other else: m |= win32traits._S_IFREG if attributes & win32traits.FILE_ATTRIBUTE_READONLY: m |= 0444 else: m |= 0666 return m def attribute_data_to_stat(info): st_mode = attributes_to_mode(info.c_dwFileAttributes) st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow) ctime = FILE_TIME_to_time_t_float(info.c_ftCreationTime) mtime = FILE_TIME_to_time_t_float(info.c_ftLastWriteTime) atime = FILE_TIME_to_time_t_float(info.c_ftLastAccessTime) result = (st_mode, 0, 0, 0, 0, 0, st_size, atime, mtime, ctime) return make_stat_result(result) def by_handle_info_to_stat(info): # similar to the one above st_mode = attributes_to_mode(info.c_dwFileAttributes) st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow) ctime = FILE_TIME_to_time_t_float(info.c_ftCreationTime) mtime = FILE_TIME_to_time_t_float(info.c_ftLastWriteTime) atime = FILE_TIME_to_time_t_float(info.c_ftLastAccessTime) # specific to fstat() st_ino = make_longlong(info.c_nFileIndexHigh, info.c_nFileIndexLow) st_nlink = info.c_nNumberOfLinks result = (st_mode, st_ino, 0, st_nlink, 0, 0, st_size, atime, mtime, ctime) return make_stat_result(result) def attributes_from_dir(l_path, data): filedata = lltype.malloc(win32traits.WIN32_FIND_DATA, flavor='raw') try: hFindFile = win32traits.FindFirstFile(l_path, filedata) if hFindFile == rwin32.INVALID_HANDLE_VALUE: return 0 win32traits.FindClose(hFindFile) data.c_dwFileAttributes = filedata.c_dwFileAttributes rffi.structcopy(data.c_ftCreationTime, filedata.c_ftCreationTime) rffi.structcopy(data.c_ftLastAccessTime, filedata.c_ftLastAccessTime) rffi.structcopy(data.c_ftLastWriteTime, filedata.c_ftLastWriteTime) data.c_nFileSizeHigh = filedata.c_nFileSizeHigh data.c_nFileSizeLow = filedata.c_nFileSizeLow return 1 finally: lltype.free(filedata, flavor='raw') def win32_stat_llimpl(path): data = lltype.malloc(win32traits.WIN32_FILE_ATTRIBUTE_DATA, flavor='raw') try: l_path = traits.str2charp(path) res = win32traits.GetFileAttributesEx( l_path, win32traits.GetFileExInfoStandard, data) errcode = rwin32.GetLastError_saved() if res == 0: if errcode == win32traits.ERROR_SHARING_VIOLATION: res = attributes_from_dir(l_path, data) errcode = rwin32.GetLastError_saved() traits.free_charp(l_path) if res == 0: raise WindowsError(errcode, "os_stat failed") return attribute_data_to_stat(data) finally: lltype.free(data, flavor='raw') def win32_fstat_llimpl(fd): handle = rwin32.get_osfhandle(fd) filetype = win32traits.GetFileType(handle) if filetype == win32traits.FILE_TYPE_CHAR: # console or LPT device return make_stat_result( (win32traits._S_IFCHR, 0, 0, 0, 0, 0, 0, 0, 0, 0)) elif filetype == win32traits.FILE_TYPE_PIPE: # socket or named pipe return make_stat_result( (win32traits._S_IFIFO, 0, 0, 0, 0, 0, 0, 0, 0, 0)) elif filetype == win32traits.FILE_TYPE_UNKNOWN: error = rwin32.GetLastError_saved() if error != 0: raise WindowsError(error, "os_fstat failed") # else: unknown but valid file # normal disk file (FILE_TYPE_DISK) info = lltype.malloc(win32traits.BY_HANDLE_FILE_INFORMATION, flavor='raw', zero=True) try: res = win32traits.GetFileInformationByHandle(handle, info) if res == 0: raise WindowsError(rwin32.GetLastError_saved(), "os_fstat failed") return by_handle_info_to_stat(info) finally: lltype.free(info, flavor='raw') if name == 'fstat': return win32_fstat_llimpl else: return win32_stat_llimpl