2022-07-26 06:24:58 +00:00
|
|
|
// Copyright (C) 2022 The Syncthing Authors.
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
package fs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strconv"
|
2022-08-12 05:48:00 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
2022-07-26 06:24:58 +00:00
|
|
|
|
|
|
|
"github.com/syncthing/syncthing/lib/protocol"
|
|
|
|
)
|
|
|
|
|
|
|
|
// unixPlatformData is used on all platforms, because apart from being the
|
|
|
|
// implementation for BasicFilesystem on Unixes it's also the implementation
|
|
|
|
// in fakeFS.
|
2022-09-14 07:50:55 +00:00
|
|
|
func unixPlatformData(fs Filesystem, name string, userCache *userCache, groupCache *groupCache, scanOwnership, scanXattrs bool, xattrFilter XattrFilter) (protocol.PlatformData, error) {
|
|
|
|
var pd protocol.PlatformData
|
|
|
|
if scanOwnership {
|
|
|
|
var ud protocol.UnixData
|
|
|
|
|
|
|
|
stat, err := fs.Lstat(name)
|
|
|
|
if err != nil {
|
|
|
|
return protocol.PlatformData{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ud.UID = stat.Owner()
|
|
|
|
if user := userCache.lookup(strconv.Itoa(ud.UID)); user != nil {
|
|
|
|
ud.OwnerName = user.Username
|
|
|
|
} else if ud.UID == 0 {
|
|
|
|
// We couldn't look up a name, but UID zero should be "root". This
|
|
|
|
// fixup works around the (unlikely) situation where the ownership
|
|
|
|
// is 0:0 but we can't look up a name for either uid zero or gid
|
|
|
|
// zero. If that were the case we'd return a zero PlatformData which
|
|
|
|
// wouldn't get serialized over the wire and the other side would
|
|
|
|
// assume a lack of ownership info...
|
|
|
|
ud.OwnerName = "root"
|
|
|
|
}
|
|
|
|
|
|
|
|
ud.GID = stat.Group()
|
|
|
|
if group := groupCache.lookup(strconv.Itoa(ud.GID)); group != nil {
|
|
|
|
ud.GroupName = group.Name
|
|
|
|
} else if ud.GID == 0 {
|
|
|
|
ud.GroupName = "root"
|
|
|
|
}
|
2022-07-26 06:24:58 +00:00
|
|
|
|
2022-09-14 07:50:55 +00:00
|
|
|
pd.Unix = &ud
|
2022-07-26 06:24:58 +00:00
|
|
|
}
|
|
|
|
|
2022-09-14 07:50:55 +00:00
|
|
|
if scanXattrs {
|
|
|
|
xattrs, err := fs.GetXattr(name, xattrFilter)
|
|
|
|
if err != nil {
|
|
|
|
return protocol.PlatformData{}, err
|
|
|
|
}
|
|
|
|
pd.SetXattrs(xattrs)
|
2022-07-26 06:24:58 +00:00
|
|
|
}
|
|
|
|
|
2022-09-14 07:50:55 +00:00
|
|
|
return pd, nil
|
2022-07-26 06:24:58 +00:00
|
|
|
}
|
2022-08-12 05:48:00 +00:00
|
|
|
|
|
|
|
type valueCache[K comparable, V any] struct {
|
|
|
|
validity time.Duration
|
|
|
|
fill func(K) (V, error)
|
|
|
|
|
|
|
|
mut sync.Mutex
|
|
|
|
cache map[K]cacheEntry[V]
|
|
|
|
}
|
|
|
|
|
|
|
|
type cacheEntry[V any] struct {
|
|
|
|
value V
|
|
|
|
when time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
func newValueCache[K comparable, V any](validity time.Duration, fill func(K) (V, error)) *valueCache[K, V] {
|
|
|
|
return &valueCache[K, V]{
|
|
|
|
validity: validity,
|
|
|
|
fill: fill,
|
|
|
|
cache: make(map[K]cacheEntry[V]),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *valueCache[K, V]) lookup(key K) V {
|
|
|
|
c.mut.Lock()
|
|
|
|
defer c.mut.Unlock()
|
|
|
|
if e, ok := c.cache[key]; ok && time.Since(e.when) < c.validity {
|
|
|
|
return e.value
|
|
|
|
}
|
|
|
|
var e cacheEntry[V]
|
|
|
|
if val, err := c.fill(key); err == nil {
|
|
|
|
e.value = val
|
|
|
|
}
|
|
|
|
e.when = time.Now()
|
|
|
|
c.cache[key] = e
|
|
|
|
return e.value
|
|
|
|
}
|