ronantakizawa/codereview-bench huggingface dataset:
Repository: syncthing/syncthing
File: lib/osutil/net.go (Go)

Code before:
	"strings"

	"github.com/wlynxg/anet"
)

// GetInterfaceAddrs returns the IP networks of all interfaces that are up.
// Point-to-point interfaces are exluded unless includePtP is true.
func GetInterfaceAddrs(includePtP bool) ([]*net.IPNet, error) {
	intfs, err := anet.Interfaces()
	if err != nil {
		return nil, err
	}
	var addrs []net.Addr

	for i := range intfs {
		intf := intfs[i]

		if intf.Flags&net.FlagRunning == 0 {
			continue
		}
		if !includePtP && intf.Flags&net.FlagPointToPoint != 0 {
			// Point-to-point interfaces are typically VPNs and similar
			// which, for our purposes, do not qualify as LANs.
			continue
		}
		intfAddrs, err := anet.InterfaceAddrsByInterface(&intfs[i])
		if err != nil {
			return nil, err
		}
		addrs = append(addrs, intfAddrs...)
	}

	nets := make([]*net.IPNet, 0, len(addrs))

	for _, addr := range addrs {
		net, ok := addr.(*net.IPNet)
		if ok {
			nets = append(nets, net)
		}
	}
	return nets, nil
}

func IPFromString(addr string) net.IP {
	// strip the port
	host, _, err := net.SplitHostPort(addr)
	if err != nil {
		host = addr
	}
	// strip IPv6 zone identifier
	host, _, _ = strings.Cut(host, "%")

Review comment (suggestion):
```suggestion
		intfAddrs, err := anet.InterfaceAddrsByInterface(&intf)
```

Code after:
	"strings"

	"github.com/wlynxg/anet"
)

// GetInterfaceAddrs returns the IP networks of all interfaces that are up.
// Point-to-point interfaces are exluded unless includePtP is true.
func GetInterfaceAddrs(includePtP bool) ([]*net.IPNet, error) {
	intfs, err := anet.Interfaces()
	if err != nil {
		return nil, err
	}
	var addrs []net.Addr

	for i := range intfs {
		intf := intfs[i]

		if intf.Flags&net.FlagRunning == 0 {
			continue
		}
		if !includePtP && intf.Flags&net.FlagPointToPoint != 0 {
			// Point-to-point interfaces are typically VPNs and similar
			// which, for our purposes, do not qualify as LANs.
			continue
		}
		intfAddrs, err := anet.InterfaceAddrsByInterface(&intf)
		if err != nil {
			return nil, err
		}
		addrs = append(addrs, intfAddrs...)
	}

	nets := make([]*net.IPNet, 0, len(addrs))

	for _, addr := range addrs {
		net, ok := addr.(*net.IPNet)
		if ok {
			nets = append(nets, net)
		}
	}
	return nets, nil
}

func IPFromString(addr string) net.IP {
	// strip the port
	host, _, err := net.SplitHostPort(addr)
	if err != nil {
		host = addr
	}
	// strip IPv6 zone identifier
	host, _, _ = strings.Cut(host, "%")
Repository: syncthing/syncthing
File: lib/netutil/netutil.go (Go)

Code before:
	"net"
	"net/url"
	"os"

	"github.com/jackpal/gateway"
)

// Address constructs a URL from the given network and hostname.
func AddressURL(network, host string) string {
	u := url.URL{
		Scheme: network,
		Host:   host,
	}
	return u.String()
}

// Gateway returns the IP address of the default network gateway.
func Gateway() (ip net.IP, err error) {
	ip, err = gateway.DiscoverGateway()
	if err != nil {
		// Fails on Android 14+ due to permission denied error when reading
		// /proc/net/route. The wrapper may give a hint then because it is
		// able to discover the gateway from java code.
		if v := os.Getenv("ANDROID_NET_GATEWAY_IPV4"); v != "" {
			ip = net.ParseIP(v)
			return ip, nil
		}
		return ip, err
	}
	return ip, nil
}


Review comment (bug):
we should check if `ip` is nil and return an error here, since `net.ParseIP` doesn't for some reason.

```go
ip = net.ParseIP(v)
if ip == nil {
    return nil, fmt.Errorf("%q: invalid IP", v)
}
```

or something

Code after:
	"fmt"
	"net"
	"net/url"
	"os"

	"github.com/jackpal/gateway"
)

// Address constructs a URL from the given network and hostname.
func AddressURL(network, host string) string {
	u := url.URL{
		Scheme: network,
		Host:   host,
	}
	return u.String()
}

// Gateway returns the IP address of the default network gateway.
func Gateway() (ip net.IP, err error) {
	ip, err = gateway.DiscoverGateway()
	if err != nil {
		// Fails on Android 14+ due to permission denied error when reading
		// /proc/net/route. The wrapper may give a hint then because it is
		// able to discover the gateway from java code.
		if v := os.Getenv("FALLBACK_NET_GATEWAY_IPV4"); v != "" {
			ip = net.ParseIP(v)
			if ip == nil {
				return nil, fmt.Errorf("%q: invalid IP", v)
			}
			return ip, nil
		}
		return ip, err
	}
	return ip, nil
}
Repository: syncthing/syncthing
File: lib/netutil/netutil.go (Go)

Code before:
import (
	"fmt"
	"net"
	"net/url"
	"os"

	"github.com/jackpal/gateway"
)

// Address constructs a URL from the given network and hostname.
func AddressURL(network, host string) string {
	u := url.URL{
		Scheme: network,
		Host:   host,
	}
	return u.String()
}

// Gateway returns the IP address of the default network gateway.
func Gateway() (ip net.IP, err error) {
	ip, err = gateway.DiscoverGateway()
	if err != nil {
		// Fails on Android 14+ due to permission denied error when reading
		// /proc/net/route. The wrapper may give a hint then because it is
		// able to discover the gateway from java code.
		if v := os.Getenv("ANDROID_NET_GATEWAY_IPV4"); v != "" {
			ip = net.ParseIP(v)
			if ip == nil {
				return nil, fmt.Errorf("%q: invalid IP", v)
			}
			return ip, nil
		}
		return ip, err
	}
	return ip, nil
}


Review comment (suggestion):
I'd drop `ANDROID` from the name, could be used on any system. And probably that's not even a hypothetical, I'd be surprised if iOS allowed this kind of access. I'd go with `FALLBACK_NET_GATEWAY_IPV4`.

Code after:
import (
	"fmt"
	"net"
	"net/url"
	"os"

	"github.com/jackpal/gateway"
)

// Address constructs a URL from the given network and hostname.
func AddressURL(network, host string) string {
	u := url.URL{
		Scheme: network,
		Host:   host,
	}
	return u.String()
}

// Gateway returns the IP address of the default network gateway.
func Gateway() (ip net.IP, err error) {
	ip, err = gateway.DiscoverGateway()
	if err != nil {
		// Fails on Android 14+ due to permission denied error when reading
		// /proc/net/route. The wrapper may give a hint then because it is
		// able to discover the gateway from java code.
		if v := os.Getenv("FALLBACK_NET_GATEWAY_IPV4"); v != "" {
			ip = net.ParseIP(v)
			if ip == nil {
				return nil, fmt.Errorf("%q: invalid IP", v)
			}
			return ip, nil
		}
		return ip, err
	}
	return ip, nil
}
Repository: syncthing/syncthing
File: internal/db/sqlite/sql/migrations/folder/04-alter-blocks-tables.sql (SQL)

Code before:
-- Copyright (C) 2025 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/.

-- Copy blocks to new table with fewer indexes

CREATE TABLE IF NOT EXISTS blocks_v4 (
    hash BLOB NOT NULL,
    blocklist_hash BLOB NOT NULL,
    idx INTEGER NOT NULL,
    offset INTEGER NOT NULL,
    size INTEGER NOT NULL,
    PRIMARY KEY (hash, blocklist_hash, idx)
) STRICT, WITHOUT ROWID
;

INSERT INTO blocks_v4 (hash, blocklist_hash, idx, offset, size)
SELECT hash, blocklist_hash, idx, offset, size FROM blocks
;

DROP TABLE blocks
;

ALTER TABLE blocks_v4 RENAME TO blocks
;

-- Copy blocklists to new table with fewer indexes

CREATE TABLE IF NOT EXISTS blocklists_v4 (
    blocklist_hash BLOB NOT NULL PRIMARY KEY,
    blprotobuf BLOB NOT NULL
) STRICT, WITHOUT ROWID
;

INSERT INTO blocklists_v4 (blocklist_hash, blprotobuf)
SELECT blocklist_hash, blprotobuf FROM blocklists
;

DROP TABLE blocklists
;

ALTER TABLE blocklists_v4 RENAME TO blocklists
;

Review comment (suggestion):
```suggestion
SELECT hash, blocklist_hash, idx, offset, size FROM blocks ORDER BY hash, blocklist_hash, idx
```

Code after:
-- Copyright (C) 2025 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/.

-- Copy blocks to new table with fewer indexes

DROP TABLE IF EXISTS blocks_v4
;

CREATE TABLE blocks_v4 (
    hash BLOB NOT NULL,
    blocklist_hash BLOB NOT NULL,
    idx INTEGER NOT NULL,
    offset INTEGER NOT NULL,
    size INTEGER NOT NULL,
    PRIMARY KEY (hash, blocklist_hash, idx)
) STRICT, WITHOUT ROWID
;

INSERT INTO blocks_v4 (hash, blocklist_hash, idx, offset, size)
SELECT hash, blocklist_hash, idx, offset, size FROM blocks ORDER BY hash, blocklist_hash, idx
;

DROP TABLE blocks
;

ALTER TABLE blocks_v4 RENAME TO blocks
;

-- Copy blocklists to new table with fewer indexes

DROP TABLE IF EXISTS blocklists_v4
;

CREATE TABLE blocklists_v4 (
    blocklist_hash BLOB NOT NULL PRIMARY KEY,
    blprotobuf BLOB NOT NULL
) STRICT, WITHOUT ROWID
;

INSERT INTO blocklists_v4 (blocklist_hash, blprotobuf)
SELECT blocklist_hash, blprotobuf FROM blocklists ORDER BY blocklist_hash
;
Repository: syncthing/syncthing
File: internal/db/sqlite/sql/migrations/folder/04-alter-blocks-tables.sql (SQL)

Code before:
    offset INTEGER NOT NULL,
    size INTEGER NOT NULL,
    PRIMARY KEY (hash, blocklist_hash, idx)
) STRICT, WITHOUT ROWID
;

INSERT INTO blocks_v4 (hash, blocklist_hash, idx, offset, size)
SELECT hash, blocklist_hash, idx, offset, size FROM blocks
;

DROP TABLE blocks
;

ALTER TABLE blocks_v4 RENAME TO blocks
;

-- Copy blocklists to new table with fewer indexes

CREATE TABLE IF NOT EXISTS blocklists_v4 (
    blocklist_hash BLOB NOT NULL PRIMARY KEY,
    blprotobuf BLOB NOT NULL
) STRICT, WITHOUT ROWID
;

INSERT INTO blocklists_v4 (blocklist_hash, blprotobuf)
SELECT blocklist_hash, blprotobuf FROM blocklists
;

DROP TABLE blocklists
;

ALTER TABLE blocklists_v4 RENAME TO blocklists
;


Review comment (suggestion):
```suggestion
SELECT blocklist_hash, blprotobuf FROM blocklists ORDER BY blocklist_hash
```

Code after:
    hash BLOB NOT NULL,
    blocklist_hash BLOB NOT NULL,
    idx INTEGER NOT NULL,
    offset INTEGER NOT NULL,
    size INTEGER NOT NULL,
    PRIMARY KEY (hash, blocklist_hash, idx)
) STRICT, WITHOUT ROWID
;

INSERT INTO blocks_v4 (hash, blocklist_hash, idx, offset, size)
SELECT hash, blocklist_hash, idx, offset, size FROM blocks ORDER BY hash, blocklist_hash, idx
;

DROP TABLE blocks
;

ALTER TABLE blocks_v4 RENAME TO blocks
;

-- Copy blocklists to new table with fewer indexes

DROP TABLE IF EXISTS blocklists_v4
;

CREATE TABLE blocklists_v4 (
    blocklist_hash BLOB NOT NULL PRIMARY KEY,
    blprotobuf BLOB NOT NULL
) STRICT, WITHOUT ROWID
;

INSERT INTO blocklists_v4 (blocklist_hash, blprotobuf)
SELECT blocklist_hash, blprotobuf FROM blocklists ORDER BY blocklist_hash
;

DROP TABLE blocklists
;

ALTER TABLE blocklists_v4 RENAME TO blocklists
;
Repository: syncthing/syncthing
File: internal/db/sqlite/sql/migrations/folder/04-alter-blocks-tables.sql (SQL)

Code before:
-- Copyright (C) 2025 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/.

-- Copy blocks to new table with fewer indexes

CREATE TABLE IF NOT EXISTS blocks_v4 (
    hash BLOB NOT NULL,
    blocklist_hash BLOB NOT NULL,
    idx INTEGER NOT NULL,
    offset INTEGER NOT NULL,
    size INTEGER NOT NULL,
    PRIMARY KEY (hash, blocklist_hash, idx)
) STRICT, WITHOUT ROWID
;

INSERT INTO blocks_v4 (hash, blocklist_hash, idx, offset, size)
SELECT hash, blocklist_hash, idx, offset, size FROM blocks ORDER BY hash, blocklist_hash, idx
;

DROP TABLE blocks
;

ALTER TABLE blocks_v4 RENAME TO blocks
;

-- Copy blocklists to new table with fewer indexes

CREATE TABLE IF NOT EXISTS blocklists_v4 (
    blocklist_hash BLOB NOT NULL PRIMARY KEY,
    blprotobuf BLOB NOT NULL
) STRICT, WITHOUT ROWID

Review comment (bug):
Shouldn't we fail if it exists - it should never? And to avoid failing if for some reason the table is there, do a `DROP blocks_v4 IF EXISTS` first - comes at the downside that if `blocks` doesn't exist either, we then have no more blocks. So probably just fail?

Code after:
-- Copyright (C) 2025 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/.

-- Copy blocks to new table with fewer indexes

DROP TABLE IF EXISTS blocks_v4
;

CREATE TABLE blocks_v4 (
    hash BLOB NOT NULL,
    blocklist_hash BLOB NOT NULL,
    idx INTEGER NOT NULL,
    offset INTEGER NOT NULL,
    size INTEGER NOT NULL,
    PRIMARY KEY (hash, blocklist_hash, idx)
) STRICT, WITHOUT ROWID
;

INSERT INTO blocks_v4 (hash, blocklist_hash, idx, offset, size)
SELECT hash, blocklist_hash, idx, offset, size FROM blocks ORDER BY hash, blocklist_hash, idx
;

DROP TABLE blocks
;

ALTER TABLE blocks_v4 RENAME TO blocks
;

-- Copy blocklists to new table with fewer indexes

DROP TABLE IF EXISTS blocklists_v4
Repository: syncthing/syncthing
File: internal/db/sqlite/folderdb_open.go (Go)

Code before:
	}

	base, err := openBase(path, 1, pragmas, schemas, nil)
	if err != nil {
		return nil, err
	}

	fdb := &folderDB{
		folderID:        folder,
		baseDB:          base,
		deleteRetention: deleteRetention,
	}

	// Touch device IDs that should always exist and have a low index
	// numbers, and will never change
	fdb.localDeviceIdx, _ = fdb.deviceIdxLocked(protocol.LocalDeviceID)
	fdb.tplInput["LocalDeviceIdx"] = fdb.localDeviceIdx

	return fdb, nil
}

func (s *folderDB) deviceIdxLocked(deviceID protocol.DeviceID) (int64, error) {
	devStr := deviceID.String()
	var idx int64
	if err := s.stmt(`
		INSERT OR IGNORE INTO devices(device_id)
		VALUES (?)
		ON CONFLICT(device_id) DO UPDATE
			SET device_id = excluded.device_id
		RETURNING idx
	`).Get(&idx, devStr); err != nil {
		return 0, wrap(err)
	}

	return idx, nil
}


Review comment (suggestion):
```suggestion
		INSERT INTO devices(device_id)
```
unneeded.

Code after:
	}

	base, err := openBase(path, 1, pragmas, schemas, nil)
	if err != nil {
		return nil, err
	}

	fdb := &folderDB{
		folderID:        folder,
		baseDB:          base,
		deleteRetention: deleteRetention,
	}

	// Touch device IDs that should always exist and have a low index
	// numbers, and will never change
	fdb.localDeviceIdx, _ = fdb.deviceIdxLocked(protocol.LocalDeviceID)
	fdb.tplInput["LocalDeviceIdx"] = fdb.localDeviceIdx

	return fdb, nil
}

func (s *folderDB) deviceIdxLocked(deviceID protocol.DeviceID) (int64, error) {
	devStr := deviceID.String()
	var idx int64
	if err := s.stmt(`
		INSERT INTO devices(device_id)
		VALUES (?)
		ON CONFLICT(device_id) DO UPDATE
			SET device_id = excluded.device_id
		RETURNING idx
	`).Get(&idx, devStr); err != nil {
		return 0, wrap(err)
	}

	return idx, nil
}
Repository: syncthing/syncthing
File: internal/db/sqlite/sql/migrations/folder/05-normalize-files.sql (SQL)

Code before:
-- Copyright (C) 2025 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/.

-- Grab all uniqe names into the names table

INSERT INTO file_names (idx, name) SELECT DISTINCT null, name FROM files
;

-- Grab all unique versions into the versions table

INSERT INTO file_versions (idx, version) SELECT DISTINCT null, version FROM files
;

-- Create the new files table

DROP TABLE IF EXISTS files_v5
;

CREATE TABLE files_v5 (
    device_idx INTEGER NOT NULL,
    sequence INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    remote_sequence INTEGER,
    name_idx INTEGER NOT NULL, -- changed
    type INTEGER NOT NULL,
    modified INTEGER NOT NULL,
    size INTEGER NOT NULL,
    version_idx INTEGER NOT NULL, -- changed
    deleted INTEGER NOT NULL,
    local_flags INTEGER NOT NULL,

Review comment (suggestion):
```suggestion
-- Grab all unique names into the names table
```

Code after:
-- Copyright (C) 2025 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/.

-- Grab all unique names into the names table

INSERT INTO file_names (idx, name) SELECT DISTINCT null, name FROM files
;

-- Grab all unique versions into the versions table

INSERT INTO file_versions (idx, version) SELECT DISTINCT null, version FROM files
;

-- Create the new files table

DROP TABLE IF EXISTS files_v5
;

CREATE TABLE files_v5 (
    device_idx INTEGER NOT NULL,
    sequence INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    remote_sequence INTEGER,
    name_idx INTEGER NOT NULL, -- changed
    type INTEGER NOT NULL,
    modified INTEGER NOT NULL,
    size INTEGER NOT NULL,
    version_idx INTEGER NOT NULL, -- changed
    deleted INTEGER NOT NULL,
    local_flags INTEGER NOT NULL,
Repository: syncthing/syncthing
File: lib/fs/casefs.go (Go)

Code before:
func (f *caseFilesystem) checkCaseExisting(name string) error {
	realName, err := f.realCase(name)
	if IsNotExist(err) {
		// It did exist just before -> cache is outdated, try again
		f.dropCache()
		realName, err = f.realCase(name)
	}
	if err != nil {
		return err
	}
	// We normalize the normalization (hah!) of the strings before
	// comparing, as we don't want to treat a normalization difference as a
	// case conflict.
	if norm.NFC.String(realName) != norm.NFC.String(name) {
		return &CaseConflictError{name, realName}
	}
	return nil
}

type defaultRealCaser struct {
	cache *caseCache
	fs    Filesystem
}

type caseCache struct {
	*lru.TwoQueueCache[string, *caseNode]

	mut sync.Mutex
}

func newCaseCache() *caseCache {
	cache, err := lru.New2Q[string, *caseNode](caseCacheItemLimit)
	// New2Q only errors if given invalid parameters, which we don't.
	if err != nil {
		panic(err)
	}
	return &caseCache{
		TwoQueueCache: cache,
	}
}

func (r *defaultRealCaser) realCase(name string) (string, error) {
	realName := "."
	if name == realName {
		return realName, nil
	}

	for _, comp := range PathComponents(name) {
		node := r.getExpireAdd(realName)

		if node.err != nil {

Review comment (performance):
nit: I don't think there's any need for this to be a pointer, we do already handle `caseCache` instances as pointers (and must to avoid copying the mutex). It was a pointer before the referenced change, but I don't see any reason for it to be a pointer there/in history either.

Code after:
func (f *caseFilesystem) checkCaseExisting(name string) error {
	realName, err := f.realCase(name)
	if IsNotExist(err) {
		// It did exist just before -> cache is outdated, try again
		f.dropCache()
		realName, err = f.realCase(name)
	}
	if err != nil {
		return err
	}
	// We normalize the normalization (hah!) of the strings before
	// comparing, as we don't want to treat a normalization difference as a
	// case conflict.
	if norm.NFC.String(realName) != norm.NFC.String(name) {
		return &CaseConflictError{name, realName}
	}
	return nil
}

type defaultRealCaser struct {
	cache *caseCache
	fs    Filesystem
}

type caseCache struct {
	*lru.TwoQueueCache[string, *caseNode]

	mut sync.Mutex
}

func newCaseCache() *caseCache {
	cache, err := lru.New2Q[string, *caseNode](caseCacheItemLimit)
	// New2Q only errors if given invalid parameters, which we don't.
	if err != nil {
		panic(err)
	}
	return &caseCache{
		TwoQueueCache: cache,
	}
}

func (r *defaultRealCaser) realCase(name string) (string, error) {
	realName := "."
	if name == realName {
		return realName, nil
	}

	for _, comp := range PathComponents(name) {
		node := r.cache.getExpireAdd(realName, r.fs)

		if node.err != nil {
Repository: syncthing/syncthing
File: lib/fs/casefs.go (Go)

Code before:
			return "", node.err
		}

		// Try to find a direct or case match
		if _, ok := node.children[comp]; !ok {
			comp, ok = node.lowerToReal[UnicodeLowercaseNormalized(comp)]
			if !ok {
				return "", ErrNotExist
			}
		}

		realName = filepath.Join(realName, comp)
	}

	return realName, nil
}

func (r *defaultRealCaser) dropCache() {
	r.cache.Purge()
}

// getExpireAdd gets an entry for the given key. If no entry exists, or it is
// expired a new one is created and added to the cache.
func (r *defaultRealCaser) getExpireAdd(key string) *caseNode {
	r.cache.mut.Lock()
	defer r.cache.mut.Unlock()
	node, ok := r.cache.Get(key)
	if !ok {
		node := newCaseNode(key, r.fs)
		r.cache.Add(key, node)
		return node
	}
	if node.expires.Before(time.Now()) {
		node = newCaseNode(key, r.fs)
		r.cache.Add(key, node)
	}
	return node
}

// The keys to children are "real", case resolved names of the path
// component this node represents (i.e. containing no path separator).
// lowerToReal is a map of lowercase path components (as in UnicodeLowercase)
// to their corresponding "real", case resolved names.
// A node is created empty and populated using once. If an error occurs the node
// is removed from cache and the error stored in err, such that anyone that
// already got the node doesn't try to access the nil maps.
type caseNode struct {
	expires     time.Time
	lowerToReal map[string]string
	children    map[string]struct{}
	err         error

Review comment (performance):
optional, nit: Now that the lock is part of the cache again, might be more readable for this to be a method on `caseCache`  (revert to state before the referenced change) passing the filesystem as a parameter.

Code after:
			return "", node.err
		}

		// Try to find a direct or case match
		if _, ok := node.children[comp]; !ok {
			comp, ok = node.lowerToReal[UnicodeLowercaseNormalized(comp)]
			if !ok {
				return "", ErrNotExist
			}
		}

		realName = filepath.Join(realName, comp)
	}

	return realName, nil
}

func (r *defaultRealCaser) dropCache() {
	r.cache.Purge()
}

// getExpireAdd gets an entry for the given key. If no entry exists, or it is
// expired a new one is created and added to the cache.
func (c *caseCache) getExpireAdd(key string, fs Filesystem) *caseNode {
	c.mut.Lock()
	defer c.mut.Unlock()
	node, ok := c.Get(key)
	if !ok {
		node := newCaseNode(key, fs)
		c.Add(key, node)
		return node
	}
	if node.expires.Before(time.Now()) {
		node = newCaseNode(key, fs)
		c.Add(key, node)
	}
	return node
}

// The keys to children are "real", case resolved names of the path
// component this node represents (i.e. containing no path separator).
// lowerToReal is a map of lowercase path components (as in UnicodeLowercase)
// to their corresponding "real", case resolved names.
// A node is created empty and populated using once. If an error occurs the node
// is removed from cache and the error stored in err, such that anyone that
// already got the node doesn't try to access the nil maps.
type caseNode struct {
	expires     time.Time
	lowerToReal map[string]string
	children    map[string]struct{}
	err         error