syncthing/lib/model/folder_sendrecv_windows.go

83 lines
2.2 KiB
Go

// 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 model
import (
"errors"
"os/user"
"strings"
"github.com/syncthing/syncthing/lib/protocol"
)
func (f *sendReceiveFolder) syncOwnership(file *protocol.FileInfo, path string) error {
if file.Platform.Windows == nil || file.Platform.Windows.OwnerName == "" {
// No owner data, nothing to do
return nil
}
l.Debugln("Owner name for %s is %s (group=%v)", path, file.Platform.Windows.OwnerName, file.Platform.Windows.OwnerIsGroup)
usid, gsid, err := lookupUserAndGroup(file.Platform.Windows.OwnerName, file.Platform.Windows.OwnerIsGroup)
if err != nil {
return err
}
l.Debugln("Owner for %s resolved to uid=%q gid=%q", path, usid, gsid)
return f.mtimefs.Lchown(path, usid, gsid)
}
func lookupUserAndGroup(name string, group bool) (string, string, error) {
// Look up either the the user or the group, returning the other kind as
// blank. This might seem an odd maneuver, but it matches what Chown
// wants as input and hides the ugly nested if:s down here.
if group {
gr, err := lookupWithoutDomain(name, func(name string) (string, error) {
gr, err := user.LookupGroup(name)
if err == nil {
return gr.Gid, nil
}
return "", err
})
if err != nil {
return "", "", err
}
return "", gr, nil
}
us, err := lookupWithoutDomain(name, func(name string) (string, error) {
us, err := user.Lookup(name)
if err == nil {
return us.Uid, nil
}
return "", err
})
if err != nil {
return "", "", err
}
return us, "", nil
}
func lookupWithoutDomain(name string, lookup func(s string) (string, error)) (string, error) {
// Try to look up the user by name. The username will be either a plain
// username or a qualified DOMAIN\user. We'll first try to look up
// whatever we got, if that fails, we'll try again with just the user
// part without domain.
v, err := lookup(name)
if err == nil {
return v, nil
}
parts := strings.Split(name, `\`)
if len(parts) == 2 {
if v, err := lookup(parts[1]); err == nil {
return v, nil
}
}
return "", errors.New("lookup failed")
}