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

Fix regression in windows file creation/modification times #5752

Merged
merged 3 commits into from
Nov 10, 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
1 change: 1 addition & 0 deletions newsfragments/5693.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix file creation/modification times as shown in the file explorer on Windows
vxgmichel marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 3 additions & 3 deletions parsec/core/mountpoint/winfsp_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import json
from contextlib import contextmanager
from datetime import datetime
from datetime import datetime, timezone
from functools import partial, wraps
from pathlib import PurePath
from typing import Any, Callable, Iterator, List, Tuple, TypeVar, Union, cast
Expand Down Expand Up @@ -220,8 +220,8 @@ def stat_to_file_attributes(stat: dict[str, str]) -> FILE_ATTRIBUTE:


def stat_to_winfsp_attributes(stat: dict[str, Any]) -> dict[str, Any]:
created = dt_to_filetime(datetime.fromtimestamp(stat["created"].timestamp()))
updated = dt_to_filetime(datetime.fromtimestamp(stat["updated"].timestamp()))
created = dt_to_filetime(datetime.fromtimestamp(stat["created"].timestamp(), tz=timezone.utc))
updated = dt_to_filetime(datetime.fromtimestamp(stat["updated"].timestamp(), tz=timezone.utc))
attributes = {
"creation_time": created,
"last_access_time": updated,
Expand Down
47 changes: 46 additions & 1 deletion tests/core/mountpoint/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from parsec._parsec import CoreEvent, DateTime
from parsec.api.data import EntryID, EntryName
from parsec.core import logged_core_factory
from parsec.core.fs import FsPath
from parsec.core.fs import FsPath, UserFS
from parsec.core.mountpoint import (
MountpointAlreadyMounted,
MountpointConfigurationError,
Expand Down Expand Up @@ -816,3 +816,48 @@ def check_mountpoint_paths(standard_mountpoint_path, personal_mountpoint_path):
await mountpoint_manager.mount_workspace(wid_standard),
await mountpoint_manager.mount_workspace(wid_personal),
)


@pytest.mark.trio
@pytest.mark.mountpoint
async def test_file_creation_and_modification_time(
base_mountpoint,
alice_user_fs: UserFS,
event_bus,
running_backend,
):
# Populate a bit the fs first...

wid = await alice_user_fs.workspace_create(EntryName("w"))
workspace = alice_user_fs.get_workspace(wid)

before_creation = alice_user_fs.device.time_provider.now().timestamp()
await workspace.write_bytes("/foo.txt", b"Hello world !")
after_creation = alice_user_fs.device.time_provider.now().timestamp()

# Now we can start fuse

async with mountpoint_manager_factory(
alice_user_fs, event_bus, base_mountpoint
) as mountpoint_manager:
path = trio.Path(await mountpoint_manager.mount_workspace(wid)) / "foo.txt"
stat = await path.stat()

assert before_creation <= stat.st_ctime <= stat.st_mtime <= stat.st_atime <= after_creation

before_modification = alice_user_fs.device.time_provider.now().timestamp()
assert await path.read_text() == "Hello world !"
await path.write_text("New content")
assert await path.read_text() == "New content"
after_modification = alice_user_fs.device.time_provider.now().timestamp()

stat = await path.stat()
assert (
before_creation
<= stat.st_ctime
<= after_creation
<= before_modification
<= stat.st_mtime
<= stat.st_atime
<= after_modification
)