Files
Chris LuandGitHub b8cba2982c mount: tell windows about changes made elsewhere (#10553)
* mount: tell windows about changes made elsewhere

Nothing invalidates a Windows client's cache from this side, so a file
created or removed by another mount, the S3 gateway or the filer API
stayed invisible in Explorer until the user refreshed by hand. The mount
already receives those events; they just had nowhere to go.

WFS gains a listener for every applied metadata event, and on Windows
that turns into the WinFsp notification for the path. A rename reports
both ends, since the destination's own event may never arrive when it
falls outside this mount.

* mount: report a removed directory as a directory

Entry is nil once a path is vacated, so asking it whether the thing that
went away was a directory always answered no and every removal was
reported as a file. Windows watches the two through different filters, so
a folder removed elsewhere never refreshed.

The invalidation now carries what used to be there, which the event
already knew and simply was not passing on.

* mount: report a rename destination once

The event stream already carries a second invalidation describing the new
path, so reporting RenamedTo here sent the destination twice — and always
as a create, so a moved directory arrived as a create followed by a
mkdir.
2026-08-03 22:17:09 -07:00

35 lines
1.0 KiB
Go

package winfsp
import (
"testing"
"github.com/seaweedfs/seaweedfs/weed/util"
)
// Event paths are absolute on the filer and cover the whole subscription, so
// rebasing them decides both what Windows is told and what is none of its
// business.
func TestRelativeToMount(t *testing.T) {
cases := []struct {
root string
path string
want string
ok bool
}{
{"/", "/a/b.txt", "/a/b.txt", true},
{"", "/a/b.txt", "/a/b.txt", true},
{"/buckets/data", "/buckets/data/a/b.txt", "/a/b.txt", true},
{"/buckets/data", "/buckets/data", "/", true},
{"/buckets/data", "/buckets/other/b.txt", "", false},
// A sibling whose name merely starts with the root must not match.
{"/buckets/data", "/buckets/data2/b.txt", "", false},
{"/buckets/data", "/elsewhere", "", false},
}
for _, c := range cases {
got, ok := relativeToMount(util.FullPath(c.root), util.FullPath(c.path))
if ok != c.ok || (ok && got != c.want) {
t.Errorf("root %q path %q = (%q, %v), want (%q, %v)", c.root, c.path, got, ok, c.want, c.ok)
}
}
}