Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use UTC tzinfo datetime values #252

Merged
merged 1 commit into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

* Added the property `smb_info` on `SMBDirEntry` which returns a named tuple `SMBDirEntryInformation` containing metadata already retrieved in the `scandir` operation.
* This avoid having to call `stat()` to retrieve data like the file attributes or datetime fields that is already available
* Ensure `DateTimeField` values are set to `UTC` timezones as FILETIME values are in UTC
* Stop using `datetime.datetime.utcfromtimestamp()` as it has been deprecated

## 1.12.0 - 2023-11-09

Expand Down
7 changes: 6 additions & 1 deletion src/smbprotocol/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,12 @@ def _parse_value(self, value):
elif isinstance(value, int):
time_microseconds = (value - self.EPOCH_FILETIME) // 10
try:
datetime_value = datetime.datetime(1970, 1, 1) + datetime.timedelta(microseconds=time_microseconds)
datetime_value = datetime.datetime(
year=1970,
month=1,
day=1,
tzinfo=datetime.timezone.utc,
) + datetime.timedelta(microseconds=time_microseconds)
except OverflowError:
# This is unfortunately but 9999 is the max value a datetime can be so we just default to that
datetime_value = datetime.datetime.max
Expand Down
38 changes: 33 additions & 5 deletions tests/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import os
import uuid
from datetime import datetime
from datetime import datetime, timezone

import pytest

Expand Down Expand Up @@ -675,10 +675,24 @@ def test_parse_message(self):
assert actual["max_read_size"].get_value() == 8388608
assert actual["max_write_size"].get_value() == 8388608
assert actual["system_time"].get_value() == datetime(
year=2017, month=11, day=16, hour=10, minute=6, second=17, microsecond=378946
year=2017,
month=11,
day=16,
hour=10,
minute=6,
second=17,
microsecond=378946,
tzinfo=timezone.utc,
)
assert actual["server_start_time"].get_value() == datetime(
year=2017, month=11, day=16, hour=10, minute=3, second=19, microsecond=927194
year=2017,
month=11,
day=16,
hour=10,
minute=3,
second=19,
microsecond=927194,
tzinfo=timezone.utc,
)
assert actual["security_buffer_offset"].get_value() == 128
assert actual["security_buffer_length"].get_value() == 120
Expand Down Expand Up @@ -743,10 +757,24 @@ def test_parse_message_3_1_1(self):
assert actual["max_read_size"].get_value() == 8388608
assert actual["max_write_size"].get_value() == 8388608
assert actual["system_time"].get_value() == datetime(
year=2017, month=11, day=15, hour=11, minute=32, second=12, microsecond=1616
year=2017,
month=11,
day=15,
hour=11,
minute=32,
second=12,
microsecond=1616,
tzinfo=timezone.utc,
)
assert actual["server_start_time"].get_value() == datetime(
year=2017, month=11, day=15, hour=11, minute=27, second=26, microsecond=349606
year=2017,
month=11,
day=15,
hour=11,
minute=27,
second=26,
microsecond=349606,
tzinfo=timezone.utc,
)
assert actual["security_buffer_offset"].get_value() == 128
assert actual["security_buffer_length"].get_value() == 120
Expand Down
10 changes: 5 additions & 5 deletions tests/test_create_contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import re
import uuid
from datetime import datetime
from datetime import datetime, timezone

import pytest

Expand Down Expand Up @@ -450,7 +450,7 @@ def test_parse_message(self):
class TestSMB2CreateQueryMaximalAccessRequest:
def test_create_message(self):
message = SMB2CreateQueryMaximalAccessRequest()
message["timestamp"] = datetime.utcfromtimestamp(0)
message["timestamp"] = datetime.fromtimestamp(0, timezone.utc)
expected = b"\x00\x80\x3e\xd5\xde\xb1\x9d\x01"
actual = message.pack()
assert len(message) == 8
Expand All @@ -462,7 +462,7 @@ def test_parse_message(self):
data = actual.unpack(data)
assert len(actual) == 8
assert data == b""
assert actual["timestamp"].get_value() == datetime.utcfromtimestamp(0)
assert actual["timestamp"].get_value() == datetime.fromtimestamp(0, timezone.utc)


class TestSMB2CreateQueryMaximalAccessResponse:
Expand Down Expand Up @@ -505,7 +505,7 @@ def test_parse_message(self):
class TestSMB2CreateTimewarpToken:
def test_create_message(self):
message = SMB2CreateTimewarpToken()
message["timestamp"] = datetime.utcfromtimestamp(0)
message["timestamp"] = datetime.fromtimestamp(0, timezone.utc)
expected = b"\x00\x80\x3e\xd5\xde\xb1\x9d\x01"
actual = message.pack()
assert len(message) == 8
Expand All @@ -517,7 +517,7 @@ def test_parse_message(self):
data = actual.unpack(data)
assert len(actual) == 8
assert data == b""
assert actual["timestamp"].get_value() == datetime.utcfromtimestamp(0)
assert actual["timestamp"].get_value() == datetime.fromtimestamp(0, timezone.utc)


class TestSMB2CreateRequestLease:
Expand Down
86 changes: 43 additions & 43 deletions tests/test_file_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# MIT License (see LICENSE or https://opensource.org/licenses/MIT)

import uuid
from datetime import datetime
from datetime import datetime, timezone

from smbprotocol.file_info import (
FileAllInformation,
Expand Down Expand Up @@ -135,10 +135,10 @@ def test_parse_message(self):
class TestFileBothDirectoryInformation:
def test_create_message(self):
message = FileBothDirectoryInformation()
message["creation_time"] = datetime.utcfromtimestamp(1024)
message["last_access_time"] = datetime.utcfromtimestamp(1024)
message["last_write_time"] = datetime.utcfromtimestamp(1024)
message["change_time"] = datetime.utcfromtimestamp(1024)
message["creation_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["last_access_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["last_write_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["change_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["end_of_file"] = 4
message["allocation_size"] = 1048576
message["file_attributes"] = 32
Expand Down Expand Up @@ -197,10 +197,10 @@ def test_parse_message(self):
assert data == b""
assert actual["next_entry_offset"].get_value() == 0
assert actual["file_index"].get_value() == 0
assert actual["creation_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["last_access_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["last_write_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["change_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["creation_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["last_access_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["last_write_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["change_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["end_of_file"].get_value() == 4
assert actual["allocation_size"].get_value() == 1048576
assert actual["file_attributes"].get_value() == 32
Expand All @@ -216,10 +216,10 @@ def test_parse_message(self):
class TestFileDirectoryInformation:
def test_create_message(self):
message = FileDirectoryInformation()
message["creation_time"] = datetime.utcfromtimestamp(1024)
message["last_access_time"] = datetime.utcfromtimestamp(1024)
message["last_write_time"] = datetime.utcfromtimestamp(1024)
message["change_time"] = datetime.utcfromtimestamp(1024)
message["creation_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["last_access_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["last_write_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["change_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["end_of_file"] = 4
message["allocation_size"] = 1048576
message["file_attributes"] = 32
Expand Down Expand Up @@ -266,10 +266,10 @@ def test_parse_message(self):
assert data == b""
assert actual["next_entry_offset"].get_value() == 0
assert actual["file_index"].get_value() == 0
assert actual["creation_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["last_access_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["last_write_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["change_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["creation_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["last_access_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["last_write_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["change_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["end_of_file"].get_value() == 4
assert actual["allocation_size"].get_value() == 1048576
assert actual["file_attributes"].get_value() == 32
Expand Down Expand Up @@ -321,10 +321,10 @@ def test_parse_message(self):
class TestFileFullDirectoryInformation:
def test_create_message(self):
message = FileFullDirectoryInformation()
message["creation_time"] = datetime.utcfromtimestamp(1024)
message["last_access_time"] = datetime.utcfromtimestamp(1024)
message["last_write_time"] = datetime.utcfromtimestamp(1024)
message["change_time"] = datetime.utcfromtimestamp(1024)
message["creation_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["last_access_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["last_write_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["change_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["end_of_file"] = 4
message["allocation_size"] = 1048576
message["file_attributes"] = 32
Expand Down Expand Up @@ -373,10 +373,10 @@ def test_parse_message(self):
assert data == b""
assert actual["next_entry_offset"].get_value() == 0
assert actual["file_index"].get_value() == 0
assert actual["creation_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["last_access_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["last_write_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["change_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["creation_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["last_access_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["last_write_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["change_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["end_of_file"].get_value() == 4
assert actual["allocation_size"].get_value() == 1048576
assert actual["file_attributes"].get_value() == 32
Expand Down Expand Up @@ -442,10 +442,10 @@ def test_parse_message(self):
class TestFileIdBothDirectoryInformation:
def test_create_message(self):
message = FileIdBothDirectoryInformation()
message["creation_time"] = datetime.utcfromtimestamp(1024)
message["last_access_time"] = datetime.utcfromtimestamp(1024)
message["last_write_time"] = datetime.utcfromtimestamp(1024)
message["change_time"] = datetime.utcfromtimestamp(1024)
message["creation_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["last_access_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["last_write_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["change_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["end_of_file"] = 4
message["allocation_size"] = 1048576
message["file_attributes"] = 32
Expand Down Expand Up @@ -509,10 +509,10 @@ def test_parse_message(self):
assert data == b""
assert actual["next_entry_offset"].get_value() == 0
assert actual["file_index"].get_value() == 0
assert actual["creation_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["last_access_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["last_write_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["change_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["creation_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["last_access_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["last_write_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["change_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["end_of_file"].get_value() == 4
assert actual["allocation_size"].get_value() == 1048576
assert actual["file_attributes"].get_value() == 32
Expand All @@ -530,10 +530,10 @@ def test_parse_message(self):
class TestFileIdFullDirectoryInformation:
def test_create_message(self):
message = FileIdFullDirectoryInformation()
message["creation_time"] = datetime.utcfromtimestamp(1024)
message["last_access_time"] = datetime.utcfromtimestamp(1024)
message["last_write_time"] = datetime.utcfromtimestamp(1024)
message["change_time"] = datetime.utcfromtimestamp(1024)
message["creation_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["last_access_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["last_write_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["change_time"] = datetime.fromtimestamp(1024, timezone.utc)
message["end_of_file"] = 4
message["allocation_size"] = 1048576
message["file_attributes"] = 32
Expand Down Expand Up @@ -587,10 +587,10 @@ def test_parse_message(self):
assert data == b""
assert actual["next_entry_offset"].get_value() == 0
assert actual["file_index"].get_value() == 0
assert actual["creation_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["last_access_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["last_write_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["change_time"].get_value() == datetime.utcfromtimestamp(1024)
assert actual["creation_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["last_access_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["last_write_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["change_time"].get_value() == datetime.fromtimestamp(1024, timezone.utc)
assert actual["end_of_file"].get_value() == 4
assert actual["allocation_size"].get_value() == 1048576
assert actual["file_attributes"].get_value() == 32
Expand Down Expand Up @@ -782,7 +782,7 @@ class TestFileFsVolumeInformation:

def test_create_message(self):
message = FileFsVolumeInformation()
message["volume_creation_time"] = datetime.utcfromtimestamp(0)
message["volume_creation_time"] = datetime.fromtimestamp(0, timezone.utc)
message["volume_serial_number"] = 10
message["volume_label"] = "café"

Expand All @@ -797,7 +797,7 @@ def test_parse_message(self):
assert len(actual) == 26
assert data == b""

assert actual["volume_creation_time"].get_value() == datetime.utcfromtimestamp(0)
assert actual["volume_creation_time"].get_value() == datetime.fromtimestamp(0, timezone.utc)
assert actual["volume_serial_number"].get_value() == 10
assert actual["volume_label_length"].get_value() == 8
assert actual["supports_objects"].get_value() is False
Expand Down
Loading