mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
192 lines
8.6 KiB
Python
192 lines
8.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
import sys
|
|
import pytest
|
|
import os
|
|
import tempfile
|
|
|
|
from datetime import datetime, timedelta
|
|
import windows.utils
|
|
import windows.pycompat
|
|
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)
|
|
|
|
|
|
|
|
def test_lookup_name():
|
|
assert windows.utils.lookup_name(None, u"SYSTEM")
|
|
assert windows.utils.lookup_name(None, u"SYSTEM")[1] == gdef.PSID.from_string("S-1-5-18")
|
|
assert isinstance(windows.utils.lookup_name(None, u"SYSTEM")[0], windows.pycompat.unicode_type)
|
|
|
|
def test_lookup_sid():
|
|
domain, user = windows.utils.lookup_sid(gdef.PSID.from_string(u"S-1-5-18"))
|
|
assert isinstance(domain, windows.pycompat.unicode_type)
|
|
assert isinstance(user, windows.pycompat.unicode_type) |