Files
hakril-PythonForWindows/tests/test_winutils.py
T
2024-06-05 22:43:30 +02:00

180 lines
8.1 KiB
Python

# -*- coding: utf-8 -*-
import sys
import pytest
import os
import tempfile
from datetime import datetime, timedelta
import windows.utils
import windows.generated_def as gdef
from .pfwtest import *
if sys.version_info.major >= 3:
unicode = str
pytestmark = pytest.mark.usefixtures('check_for_gc_garbage')
ntqueryinformationfile_info_structs = {
gdef.FileAccessInformation: gdef.FILE_ACCESS_INFORMATION,
gdef.FileAlignmentInformation: gdef.FILE_ALIGNMENT_INFORMATION,
gdef.FileAllInformation: gdef.FILE_ALL_INFORMATION,
gdef.FileAttributeTagInformation: gdef.FILE_ATTRIBUTE_TAG_INFORMATION,
gdef.FileBasicInformation: gdef.FILE_BASIC_INFORMATION,
gdef.FileEaInformation: gdef.FILE_EA_INFORMATION ,
gdef.FileInternalInformation: gdef.FILE_INTERNAL_INFORMATION,
gdef.FileIoPriorityHintInformation: gdef.FILE_IO_PRIORITY_HINT_INFORMATION,
gdef.FileModeInformation: gdef.FILE_MODE_INFORMATION,
gdef.FileNetworkOpenInformation: gdef.FILE_NETWORK_OPEN_INFORMATION,
gdef.FileNameInformation: gdef.FILE_NAME_INFORMATION,
gdef.FilePositionInformation: gdef.FILE_POSITION_INFORMATION,
gdef.FileStandardInformation: gdef.FILE_STANDARD_INFORMATION,
gdef.FileIsRemoteDeviceInformation: gdef.FILE_IS_REMOTE_DEVICE_INFORMATION,
}
def test_query_file_information():
f = open(r"C:\windows\system32\ntdll.dll")
handle = windows.utils.get_handle_from_file(f)
for info_class, info_struct in ntqueryinformationfile_info_structs.items():
res = windows.utils.query_file_information(handle, info_class) # Fail should raise
resf = windows.utils.query_file_information(f, info_class) # Try with the file directly
# Check return type
assert isinstance(res, info_struct)
assert isinstance(resf, info_struct)
ntqueryvolumeinformationfile_info_structs = {
gdef.FileFsAttributeInformation: gdef.FILE_FS_ATTRIBUTE_INFORMATION,
gdef.FileFsControlInformation: gdef.FILE_FS_CONTROL_INFORMATION,
gdef.FileFsDeviceInformation: gdef.FILE_FS_DEVICE_INFORMATION,
# gdef.FileFsDriverPathInformation: gdef.FILE_FS_DRIVER_PATH_INFORMATION, # Not handled for now
gdef.FileFsFullSizeInformation: gdef.FILE_FS_FULL_SIZE_INFORMATION,
gdef.FileFsObjectIdInformation: gdef.FILE_FS_OBJECTID_INFORMATION,
gdef.FileFsSizeInformation: gdef.FILE_FS_SIZE_INFORMATION,
gdef.FileFsVolumeInformation: gdef.FILE_FS_VOLUME_INFORMATION,
gdef.FileFsSectorSizeInformation: gdef.FILE_FS_SECTOR_SIZE_INFORMATION,
}
def test_query_volume_information():
f = open(r"C:\windows\system32\ntdll.dll")
handle = windows.utils.get_handle_from_file(f)
for info_class, info_struct in ntqueryvolumeinformationfile_info_structs.items():
res = windows.utils.query_volume_information(handle, info_class) # Fail should raise
resf = windows.utils.query_volume_information(f, info_class) # Try with the file directly
# Check return type
assert isinstance(res, info_struct)
assert isinstance(resf, info_struct)
def date_equals(d1, d2, acceptable_delta=timedelta(microseconds=1)):
if d2 > d1:
delta = d2 - d1
else:
delta = d1 - d2
return delta <= acceptable_delta
def test_datetime_from_filetime():
FILENAME = "C:\\windows\\system32\\ntdll.dll"
f = open(FILENAME)
datetime_from_filetime = windows.utils.datetime_from_filetime
# Compare to os.stat
stats = os.stat(FILENAME)
utc_satime = datetime.utcfromtimestamp(stats.st_atime)
utc_smtime = datetime.utcfromtimestamp(stats.st_mtime)
utc_sctime = datetime.utcfromtimestamp(stats.st_ctime)
# Compare to NtQueryInformationFile
fileinfo = windows.utils.query_file_information(f, gdef.FileBasicInformation)
utc_watime = datetime_from_filetime(fileinfo.LastAccessTime)
utc_wmtime = datetime_from_filetime(fileinfo.LastWriteTime)
utc_wctime = datetime_from_filetime(fileinfo.CreationTime)
assert date_equals(utc_satime, utc_watime)
assert date_equals(utc_smtime, utc_wmtime)
assert date_equals(utc_sctime, utc_wctime)
# Test rounding
## Round-down
assert date_equals(datetime_from_filetime(131492395680727300), datetime(2017, 9, 7, 6, 32, 48, 72730))
assert date_equals(datetime_from_filetime(131492395680727304), datetime(2017, 9, 7, 6, 32, 48, 72730))
assert date_equals(datetime_from_filetime(131492395680727305), datetime(2017, 9, 7, 6, 32, 48, 72731))
assert date_equals(datetime_from_filetime(131492395680727309), datetime(2017, 9, 7, 6, 32, 48, 72731))
assert date_equals(datetime.utcfromtimestamp(1504764215.5896280), datetime_from_filetime(131492378155896280))
assert date_equals(datetime.utcfromtimestamp(1504764215.5896284), datetime_from_filetime(131492378155896284))
assert date_equals(datetime.utcfromtimestamp(1504764215.5896285), datetime_from_filetime(131492378155896285))
assert date_equals(datetime.utcfromtimestamp(1504764215.5896289), datetime_from_filetime(131492378155896289))
def test_unix_timestamp_from_filetime():
# Check date vs timestamps to be sure
assert datetime.utcfromtimestamp(1504765968.072730) == datetime(2017, 9, 7, 6, 32, 48, 72730)
assert windows.utils.unix_timestamp_from_filetime(131492395680727300) == 1504765968.072730
assert windows.utils.unix_timestamp_from_filetime(131492395680727304) == 1504765968.072730
assert datetime.utcfromtimestamp(1504765968.072731) == datetime(2017, 9, 7, 6, 32, 48, 72731)
assert windows.utils.unix_timestamp_from_filetime(131492395680727309) == 1504765968.072731
# Well py3 will round it to 1504765968.07273
# Because round(0.5) == 0 (vs 1 in py2)
assert windows.utils.unix_timestamp_from_filetime(131492395680727305) == 1504765968.072731
# Test values from https://docs.microsoft.com/en-us/cpp/atl-mfc-shared/date-type?view=vs-2019
@pytest.mark.parametrize("comtime, date", [
(0, datetime(1899, 12, 30)),
(2, datetime(1900, 1, 1)),
(5, datetime(1900, 1, 4)),
(5.25, datetime(1900, 1, 4, hour=6)),
(5.5, datetime(1900, 1, 4, hour=12)),
(5.875, datetime(1900, 1, 4, hour=21)),
(-0.25, datetime(1899, 12, 30, hour=6)),
(-0.5, datetime(1899, 12, 30, hour=12)),
(-2, datetime(1899, 12, 28)),
(-2.5, datetime(1899, 12, 28, hour=12)),
(-2.75, datetime(1899, 12, 28, hour=18)),
])
def test_datetime_from_comtime(comtime, date):
assert windows.utils.datetime_from_comdate(comtime) == date
@pytest.mark.parametrize("prefix", [
("long_ascii_prefix"),
(u'\u4e2d\u56fd\u94f6\u884c\u7f51\u94f6\u52a9\u624b'),
])
def test_long_short_path_str_unicode(prefix):
"""Test that get_short_path/get_long_path works with str/unicode path and returns unicode"""
with tempfile.NamedTemporaryFile(prefix=prefix) as f:
# Basename may be a mix of short & long path depending on version ? username ? (seen as short in github CI)
# Short for the dir + long for the filename
basename = f.name.lower()
short_name = windows.utils.get_short_path(basename).lower()
assert "~" in short_name
assert isinstance(short_name, unicode)
full_name = windows.utils.get_long_path(short_name).lower()
assert "~" not in full_name
assert isinstance(full_name, unicode)
assert len(full_name) > len(short_name)
TEST_CERT = b"""
MIIBwTCCASqgAwIBAgIQG46Uyws+67ZBOfPJCbFrRjANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQD
ExRQeXRob25Gb3JXaW5kb3dzVGVzdDAeFw0xNzA0MTIxNDM5MjNaFw0xODA0MTIyMDM5MjNaMB8x
HTAbBgNVBAMTFFB5dGhvbkZvcldpbmRvd3NUZXN0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQCRHwC/sRfXh5pc4poc85aidrudbPdya+0OeonQlf1JQ1ekf7KSfADV5FLkSQu2BzgBK9DIWTGX
XknBJIzZF03UZsVg5D67V2mnSClXucc0cGFcK4pDDt0tHeabA2GPinVe7Z6qDT4ZxPR8lKaXDdV2
Pg2hTdcGSpqaltHxph7G/QIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACcQFdOlVjYICOIyAXowQaEN
qcLpN1iWoL9UijNhTY37+U5+ycFT8QksT3Xmh9lEIqXMh121uViy2P/3p+Ek31AN9bB+BhWIM6PQ
gy+ApYDdSwTtWFARSrMqk7rRHUveYEfMw72yaOWDxCzcopEuADKrrYEute4CzZuXF9PbbgK6"""
def test_sprint_certificate():
cert = windows.crypto.Certificate.from_buffer(b64decode(TEST_CERT))
# Certificate is quite a complexe Windows structure
# With Sub-struct / Pointer & string
# It was broken on py3 -> ense this test
windows.utils.sprint(cert)