]> Cypherpunks.ru repositories - gostls13.git/commitdiff
os: force consistent mtime before running fstest on directory on Windows
authorJason A. Donenfeld <Jason@zx2c4.com>
Mon, 18 Jan 2021 14:23:16 +0000 (15:23 +0100)
committerJason A. Donenfeld <Jason@zx2c4.com>
Mon, 25 Jan 2021 15:12:58 +0000 (15:12 +0000)
FindFileNext sometimes returns a different mtime than looking at the
file directly, because the MFT on NTFS is written to lazily. In order to
keep these in sync, we use GetFileInformationByHandle to get the actual
mtime, and then write it back to the file explicitly.

Fixes #42637.

Change-Id: I774016d3ac55d0dc9b0f9c1b681516c33ba0d28a
Reviewed-on: https://go-review.googlesource.com/c/go/+/285720
Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
Trust: Jason A. Donenfeld <Jason@zx2c4.com>

src/os/os_test.go

index 698dbca91e4a3ba59a921a8a0d90004b29e85a90..ee54b4aba1ab81def7b8ae2501a70f7bf00952d5 100644 (file)
@@ -11,6 +11,7 @@ import (
        "fmt"
        "internal/testenv"
        "io"
+       "io/fs"
        "os"
        . "os"
        osexec "os/exec"
@@ -2689,6 +2690,32 @@ func TestOpenFileKeepsPermissions(t *testing.T) {
 }
 
 func TestDirFS(t *testing.T) {
+       // On Windows, we force the MFT to update by reading the actual metadata from GetFileInformationByHandle and then
+       // explicitly setting that. Otherwise it might get out of sync with FindFirstFile. See golang.org/issues/42637.
+       if runtime.GOOS == "windows" {
+               if err := filepath.WalkDir("./testdata/dirfs", func(path string, d fs.DirEntry, err error) error {
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       info, err := d.Info()
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       stat, err := Stat(path) // This uses GetFileInformationByHandle internally.
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if stat.ModTime() == info.ModTime() {
+                               return nil
+                       }
+                       if err := Chtimes(path, stat.ModTime(), stat.ModTime()); err != nil {
+                               t.Log(err) // We only log, not die, in case the test directory is not writable.
+                       }
+                       return nil
+               }); err != nil {
+                       t.Fatal(err)
+               }
+       }
        if err := fstest.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err != nil {
                t.Fatal(err)
        }