mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-16 19:18:30 +02:00
* 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.
60 lines
2.1 KiB
Go
60 lines
2.1 KiB
Go
package winfsp
|
|
|
|
import (
|
|
cgofuse "github.com/winfsp/cgofuse/fuse"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/glog"
|
|
"github.com/seaweedfs/seaweedfs/weed/mount/meta_cache"
|
|
"github.com/seaweedfs/seaweedfs/weed/util"
|
|
)
|
|
|
|
// notifier turns the mount's metadata events into the notifications Windows
|
|
// listens for. Nothing invalidates a Windows client's cache from this side, so
|
|
// without it a change made by another mount, the S3 gateway or the filer API
|
|
// stays invisible until the user refreshes by hand.
|
|
type notifier struct {
|
|
host *cgofuse.FileSystemHost
|
|
mountRoot util.FullPath
|
|
}
|
|
|
|
// notify reports one applied event. Windows wants the path relative to the
|
|
// mount, and an action describing what happened to it.
|
|
func (n *notifier) notify(invalidation meta_cache.EntryInvalidation) {
|
|
if n.host == nil {
|
|
return
|
|
}
|
|
// A rename arrives as two invalidations, one vacating the old path and one
|
|
// describing the new, so reporting RenamedTo here as well would send the
|
|
// destination twice — and as a create even when a directory moved.
|
|
if path, ok := relativeToMount(n.mountRoot, invalidation.Path); ok {
|
|
n.send(path, n.action(invalidation))
|
|
}
|
|
}
|
|
|
|
func (n *notifier) send(path string, action uint32) {
|
|
if !n.host.Notify(path, action) {
|
|
// A rejected notification only costs a stale view until the client
|
|
// looks again, so it is not worth failing an operation over.
|
|
glog.V(4).Infof("winfsp notify %s action %d rejected", path, action)
|
|
}
|
|
}
|
|
|
|
// action picks what to tell Windows happened. It cannot distinguish a created
|
|
// entry from a modified one, and Windows treats an unexpected create on an
|
|
// existing name as a refresh, so create is the safe report.
|
|
func (n *notifier) action(invalidation meta_cache.EntryInvalidation) uint32 {
|
|
if invalidation.Deleted || invalidation.Entry == nil {
|
|
// The entry is gone, so only WasDirectory still says what it was, and
|
|
// Windows watches directory and file removals through different
|
|
// filters.
|
|
if invalidation.WasDirectory {
|
|
return cgofuse.NOTIFY_RMDIR
|
|
}
|
|
return cgofuse.NOTIFY_UNLINK
|
|
}
|
|
if invalidation.Entry.GetIsDirectory() {
|
|
return cgofuse.NOTIFY_MKDIR
|
|
}
|
|
return cgofuse.NOTIFY_CREATE
|
|
}
|