| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- // 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")
- }
|