From 9eb47cf546d7e2499eab210d70050ef78087475a Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sat, 18 Jan 2025 14:11:51 +0100 Subject: reverse: advance mtime & ctime for virtual files by 10 seconds With inode number reuse and hard links, we could have returned wrong data for gocryptfs.diriv and gocryptfs.xyz.longname files, respectively (https://github.com/rfjakob/gocryptfs/issues/802). Now that this is fixed, ensure that rsync and similar tools pick up the new correct files by advancing mtime and ctime by 10 seconds, which should be more than any filesytems' timestamp granularity (FAT32 has 2 seconds). --- tests/reverse/correctness_test.go | 65 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'tests/reverse/correctness_test.go') diff --git a/tests/reverse/correctness_test.go b/tests/reverse/correctness_test.go index 8f051d0..c93c32a 100644 --- a/tests/reverse/correctness_test.go +++ b/tests/reverse/correctness_test.go @@ -363,3 +363,68 @@ func TestHardlinkedLongname(t *testing.T) { t.Errorf("Files %q have the same inode number - that's wrong!", matches) } } + +// With inode number reuse and hard links, we could have returned +// wrong data for gocryptfs.diriv and gocryptfs.xyz.longname files, respectively +// (https://github.com/rfjakob/gocryptfs/issues/802). +// +// Now that this is fixed, ensure that rsync and similar tools pick up the new +// correct files by advancing mtime and ctime by 10 seconds, which should be more +// than any filesytems' timestamp granularity (FAT32 has 2 seconds). +func TestMtimePlus10(t *testing.T) { + if plaintextnames { + t.Skip("plaintextnames mode does not have virtual files") + } + + workdirA, workdirB := newWorkdir(t) + + long := workdirA + "/" + strings.Repeat("x", 200) + if err := os.WriteFile(long, nil, 0600); err != nil { + t.Fatal(err) + } + var long_stat syscall.Stat_t + if err := syscall.Stat(long, &long_stat); err != nil { + t.Fatal(err) + } + + var workdirA_stat syscall.Stat_t + if err := syscall.Stat(workdirA, &workdirA_stat); err != nil { + t.Fatal(err) + } + + // Find and check gocryptfs.longname.*.name + matches, err := filepath.Glob(workdirB + "/gocryptfs.longname.*.name") + if err != nil { + t.Fatal(err) + } + if len(matches) != 1 { + t.Fatal(matches) + } + var name_stat syscall.Stat_t + if err := syscall.Stat(matches[0], &name_stat); err != nil { + t.Fatal(err) + } + if name_stat.Mtim.Sec != long_stat.Mtim.Sec+10 { + t.Errorf(".name file should show mtime+10") + } + if name_stat.Ctim.Sec != long_stat.Ctim.Sec+10 { + t.Errorf(".name file should show ctime+10") + } + + if deterministic_names { + // No gocryptfs.diriv + return + } + + // Check gocryptfs.diriv + var diriv_stat syscall.Stat_t + if err := syscall.Stat(workdirB+"/gocryptfs.diriv", &diriv_stat); err != nil { + t.Fatal(err) + } + if diriv_stat.Mtim.Sec != workdirA_stat.Mtim.Sec+10 { + t.Errorf("diriv file should show mtime+10") + } + if diriv_stat.Ctim.Sec != workdirA_stat.Ctim.Sec+10 { + t.Errorf("diriv file should show ctime+10") + } +} -- cgit v1.2.3