mirror of
https://github.com/borgbackup/borg.git
synced 2026-10-12 02:11:36 +00:00
win32: archive the file creation time as birthtime, not as ctime, see #8730
On Windows, stat().st_ctime is the file *creation* time and not the POSIX "metadata change time", and Python 3.12 deprecated it for that reason. Thus, do not archive it as item.ctime any more (there simply is no ctime on Windows), but archive it as item.birthtime - which is also what Python >= 3.12 gives us via st_birthtime_ns. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
95fe6ccf7c
commit
c99d03a209
+2
-1
@@ -1227,7 +1227,8 @@ class MetadataCollector:
|
||||
attrs["mtime"] = safe_ns(st.st_mtime_ns)
|
||||
if not self.noatime:
|
||||
attrs["atime"] = safe_ns(st.st_atime_ns)
|
||||
if not self.noctime:
|
||||
if not self.noctime and not is_win32:
|
||||
# win32: st_ctime is the file creation time, that is archived as birthtime, see #8730.
|
||||
attrs["ctime"] = safe_ns(st.st_ctime_ns)
|
||||
if not self.nobirthtime:
|
||||
birthtime_ns = get_birthtime_ns(st, path, fd=fd)
|
||||
|
||||
@@ -96,6 +96,9 @@ def get_birthtime_ns(st, path, fd=None):
|
||||
if hasattr(st, "st_birthtime_ns"):
|
||||
# Added in Python 3.12, but not always available.
|
||||
return st.st_birthtime_ns
|
||||
elif is_win32:
|
||||
# Python < 3.12 on win32: st_ctime is the file creation time, see #8730.
|
||||
return st.st_ctime_ns
|
||||
elif is_darwin and is_darwin_feature_64_bit_inode:
|
||||
return _get_birthtime_ns(fd or path, follow_symlinks=False)
|
||||
elif hasattr(st, "st_birthtime"):
|
||||
|
||||
@@ -175,7 +175,7 @@ def test_basic_functionality(archivers, request):
|
||||
unexpected = {"type": "modified", "added": 0, "removed": 0}
|
||||
assert unexpected not in get_changes("input/file_touched", joutput)
|
||||
if not content_only:
|
||||
# on win32, ctime is the file creation time and does not change.
|
||||
# on win32, no ctime is archived, see #8730.
|
||||
expected = {"mtime"} if is_win32 else {"mtime", "ctime"}
|
||||
assert expected.issubset({c["type"] for c in get_changes("input/file_touched", joutput)})
|
||||
else:
|
||||
@@ -274,18 +274,20 @@ def test_time_diffs(archivers, request):
|
||||
cmd(archiver, "create", "archive2", "input")
|
||||
output = cmd(archiver, "diff", "archive1", "archive2", "--format", "'{mtime}{ctime} {path}{NL}'")
|
||||
assert "mtime" in output
|
||||
assert "ctime" in output # Should show up on Windows as well since it is a new file.
|
||||
if is_win32:
|
||||
assert "ctime" not in output # win32: no ctime is archived, see #8730
|
||||
else:
|
||||
assert "ctime" in output
|
||||
|
||||
granularity_sleep()
|
||||
os.chmod("input/test_file", 0o777)
|
||||
cmd(archiver, "create", "archive3", "input")
|
||||
output = cmd(archiver, "diff", "archive2", "archive3", "--format", "'{mtime}{ctime} {path}{NL}'")
|
||||
assert "mtime" not in output
|
||||
# Checking platform because ctime should not be shown on Windows since it wasn't recreated.
|
||||
if not is_win32:
|
||||
assert "ctime" in output
|
||||
if is_win32:
|
||||
assert "ctime" not in output # win32: no ctime is archived, see #8730
|
||||
else:
|
||||
assert "ctime" not in output
|
||||
assert "ctime" in output
|
||||
|
||||
|
||||
def test_sort_by_option(archivers, request):
|
||||
|
||||
Reference in New Issue
Block a user