1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- // 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"
- "sync"
- "time"
- "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.
- 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"
- }
- pd.Unix = &ud
- }
- if scanXattrs {
- xattrs, err := fs.GetXattr(name, xattrFilter)
- if err != nil {
- return protocol.PlatformData{}, err
- }
- pd.SetXattrs(xattrs)
- }
- return pd, nil
- }
- 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
- }
|