fix(watch): capture Windows file identity before external moves

This commit is contained in:
eezd committed 2026-10-27 15:03:57 +08:00
1 parent 1a8f70ca13
commit 18bbb60a3b
4 files changed
+41 -4

No files matched your search

+7
View File
@@ -0,0 +1,7 @@
//go:build !windows
package watch
import "os"
func snapshotInfo(path string) (os.FileInfo, error) { return os.Stat(path) }
+16
View File
@@ -0,0 +1,16 @@
package watch
import (
"errors"
"os"
)
func snapshotInfo(path string) (os.FileInfo, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
// File.Stat captures the file ID from its open handle, before external renames.
info, err := file.Stat()
return info, errors.Join(err, file.Close())
}
+12 -1
View File
@@ -10,6 +10,7 @@ import (
"os"
"path/filepath"
"rawmark/internal/i18n"
"runtime"
"sort"
"strings"
"time"
@@ -135,8 +136,18 @@ func (w *Watcher) scan() (map[string]fileState, error) {
next := make(map[string]fileState, len(entries))
dirs := map[string]bool{w.v.Root(): true}
for _, e := range entries {
st := fileState{dir: e.Dir, size: e.Size, mtime: e.Info.ModTime().UnixNano(), info: e.Info}
abs := filepath.Join(w.v.Root(), filepath.FromSlash(e.Path))
info := e.Info
if runtime.GOOS == "windows" {
info, err = snapshotInfo(abs)
if errors.Is(err, fs.ErrNotExist) {
continue
}
if err != nil {
return nil, err
}
}
st := fileState{dir: e.Dir, size: info.Size(), mtime: info.ModTime().UnixNano(), info: info}
if e.Dir {
dirs[abs] = true
} else if vault.IsNote(e.Path) {
+6 -3
View File
@@ -42,6 +42,9 @@ func TestUnreadableNotePreservesSnapshot(t *testing.T) {
t.Fatal(err)
}
allowRead := testutil.DenyRead(t, p)
if _, err := os.ReadFile(p); err == nil {
t.Fatal("filesystem failure fixture did not block reading")
}
w.rescan()
if w.snap["note.md"].rev != old || scans != 0 {
t.Fatal("读取失败不能提交不完整快照或更新索引")
@@ -69,7 +72,7 @@ func TestDiff(t *testing.T) {
}
}
state := func(p, rev string) fileState {
info, err := os.Stat(filepath.Join(root, p))
info, err := snapshotInfo(filepath.Join(root, p))
if err != nil {
t.Fatal(err)
}
@@ -125,7 +128,7 @@ func TestDirectoryMovesCoverChildrenAndEmptyDirectories(t *testing.T) {
snapshot := func(dir string) map[string]fileState {
out := map[string]fileState{}
for _, rel := range []string{dir, dir + "/empty", dir + "/a.md"} {
info, err := os.Stat(filepath.Join(root, rel))
info, err := snapshotInfo(filepath.Join(root, rel))
if err != nil {
t.Fatal(err)
}
@@ -170,7 +173,7 @@ func TestImageReplacementRefreshesTree(t *testing.T) {
if err := os.WriteFile(p, []byte("image"), 0o644); err != nil {
t.Fatal(err)
}
info, err := os.Stat(p)
info, err := snapshotInfo(p)
if err != nil {
t.Fatal(err)
}