Files
Chris Lu b1fecf3b44 mount: mark windows files archived and ignore a zero timestamp (#10559)
* mount: mark windows files archived and ignore a zero timestamp

Windows synthesises NORMAL when a file reports no attributes at all, which
is not the same as ARCHIVE and is what create_fileattr_test checks.

Utimens also wrote a zero timestamp through. Windows sends zero for a field
it is not setting, and storing it put 1970 in the atime overlay, which then
overrode the entry's real time — so a file created a moment ago reported an
access time of 1970 whenever the caller asked through an open handle.
Reading the path instead went down a different route and looked right,
which is why a probe of a fresh file showed nothing wrong.

* mount: match the file type by its mask, and only treat the epoch as unset

S_IFDIR is part of the multi-bit type field rather than a flag, so masking
against it alone also matched a symlink, which shares the bit. A regular
file is now identified by the type mask.

Rejecting every timestamp at or below zero also rejected a date genuinely
before 1970. Only the epoch itself is what Windows sends for a field it is
not setting, so that is all that is refused.

create_fileattr goes back on the known-failures list: the archive fix
works and the test simply moves on to ask for READONLY too, which needs
Chflags. Taking it off was premature.

* mount: drop the time overlays when an inode is released

atimeMap and dirMtimeMap are keyed by inode and were only ever trimmed by
a random eviction at capacity. Inodes are derived from the path, so a
delete and recreate hands the same number to a different file, which then
reported the previous file's access time — a file created a moment ago
answering with a time from long before it existed.

Cleared when Forget actually releases the inode, not on every decrement:
a partial forget still has users. Forget now reports that so callers
holding state keyed by the inode know when to drop it.

* ci: keep getfileinfo listed while its access time is unexplained

Two causes have been fixed and neither closed it, so the honest state is
listed-with-a-reason rather than removed in hope.

* mount: drop timestamp overlays while the inode table is locked

Forget released the inode under the table's lock but cleaned up the
atime and dir-mtime overlays after returning from it. Inode numbers are
derived from the path, so a lookup arriving in that window is handed the
same number back and can store a time that the cleanup then deletes.

Run the cleanup at the release point instead, as a callback under the
lock. The directory-cache purge stays deferred until after the unlock,
where it has to be.

Claude-Session: https://claude.ai/code/session_01EgY2QA3iiPtiu6ww3P2EBn
2026-08-04 16:42:33 -07:00

93 lines
3.5 KiB
Plaintext

# Known winfsp-tests failures for the SeaweedFS Windows mount.
#
# One test name per line, as winfsp-tests reports it. A trailing * matches a
# prefix, so "stream_*" covers a whole group. Listed tests are excluded from
# the run; a failure in anything NOT listed fails CI, which is what catches a
# regression.
#
# Every test runs on its own in a clean directory, so an entry here is a real
# defect rather than the wreckage of the test before it. The rdwr and flush
# group is gone from this list for exactly that reason: it passes in isolation
# and only failed as collateral. Every entry below is a
# gap in the mount rather than a quirk of the suite, and the list is meant to
# shrink. Keep a reason on each group — an entry with no reason cannot be told
# apart from one nobody has looked at.
# Cannot pass by construction
# ---------------------------
# Alternate data streams: the filer stores one byte range per entry, and the
# mount exposes no second stream.
stream_*
# Reparse points: Symlink is refused, so there is nothing to resolve.
reparse_*
# Byte-range locks live in the WinFsp driver, so they never reach the mount.
lock_*
# Security descriptors
# --------------------
# The mount carries unix mode bits and no ACL, and Chown accepts and discards,
# so a descriptor written here does not read back.
create_sd_test
getsecurity_test
# Memory-mapped IO
# ----------------
# rdwr-test.c:645 compares the mapped bytes against the pattern that was
# written and finds them different. A real data mismatch, not a cascade: it
# only surfaced once each test ran on its own and this one got far enough to
# check. Worth its own investigation.
rdwr_mmap_test
# Delete semantics
# ----------------
# WinFsp advertises POSIX unlink, so a file can be deleted while handles are
# still open; the mount does not implement the delete-pending state.
delete_access_test
delete_ex_test
delete_mmap_test
delete_pending_test
# Rename semantics
# ----------------
# Rename over an open file, and rename of a directory holding open handles,
# which WinFsp is stricter about than POSIX.
rename_ex_test
rename_mmap_test
rename_open_test
exec_rename_dir_test
# File information
# ----------------
# A regular file reports as archived now, but hidden, system and readonly are
# still not round-tripped: create_fileattr gets past the archive check and then
# asks for READONLY as well, which needs Chflags. Creation time is reported as
# ctime because the raw protocol's Attr carries no field for it outside darwin.
create_fileattr_test
# getfileinfo asserts a file created a moment ago has an access time within ten
# seconds of now, and it does not. Two causes have been fixed and neither was
# it: Utimens no longer stores a zero timestamp, and the in-memory overlays are
# dropped when an inode is released so a recycled number cannot inherit an old
# time. Still unexplained, so it stays listed rather than pretended about.
getfileinfo_test
create_readonlydir_test
setfileinfo_test
# Directory enumeration
# ---------------------
# querydir_namelen only: checkName caps at 255 bytes while WinFsp counts 255
# characters. The other two are expected to pass now that "." and ".." are
# reported for non-root directories, which is what WinFsp enumerates.
querydir_namelen_test
# Name length
# -----------
# checkName caps at 255 bytes while WinFsp allows 255 characters, so a CJK
# name that is legal to Windows is rejected here.
create_namelen_test
# Sharing modes
# -------------
# Windows share-access checking on create, which the mount does not enforce.
create_share_test
create_test