folder_sendrecv_windows.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. // Copyright (C) 2022 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package model
  7. import (
  8. "errors"
  9. "os/user"
  10. "strings"
  11. "github.com/syncthing/syncthing/lib/protocol"
  12. )
  13. func (f *sendReceiveFolder) syncOwnership(file *protocol.FileInfo, path string) error {
  14. if file.Platform.Windows == nil || file.Platform.Windows.OwnerName == "" {
  15. // No owner data, nothing to do
  16. return nil
  17. }
  18. l.Debugln("Owner name for %s is %s (group=%v)", path, file.Platform.Windows.OwnerName, file.Platform.Windows.OwnerIsGroup)
  19. usid, gsid, err := lookupUserAndGroup(file.Platform.Windows.OwnerName, file.Platform.Windows.OwnerIsGroup)
  20. if err != nil {
  21. return err
  22. }
  23. l.Debugln("Owner for %s resolved to uid=%q gid=%q", path, usid, gsid)
  24. return f.mtimefs.Lchown(path, usid, gsid)
  25. }
  26. func lookupUserAndGroup(name string, group bool) (string, string, error) {
  27. // Look up either the the user or the group, returning the other kind as
  28. // blank. This might seem an odd maneuver, but it matches what Chown
  29. // wants as input and hides the ugly nested if:s down here.
  30. if group {
  31. gr, err := lookupWithoutDomain(name, func(name string) (string, error) {
  32. gr, err := user.LookupGroup(name)
  33. if err == nil {
  34. return gr.Gid, nil
  35. }
  36. return "", err
  37. })
  38. if err != nil {
  39. return "", "", err
  40. }
  41. return "", gr, nil
  42. }
  43. us, err := lookupWithoutDomain(name, func(name string) (string, error) {
  44. us, err := user.Lookup(name)
  45. if err == nil {
  46. return us.Uid, nil
  47. }
  48. return "", err
  49. })
  50. if err != nil {
  51. return "", "", err
  52. }
  53. return us, "", nil
  54. }
  55. func lookupWithoutDomain(name string, lookup func(s string) (string, error)) (string, error) {
  56. // Try to look up the user by name. The username will be either a plain
  57. // username or a qualified DOMAIN\user. We'll first try to look up
  58. // whatever we got, if that fails, we'll try again with just the user
  59. // part without domain.
  60. v, err := lookup(name)
  61. if err == nil {
  62. return v, nil
  63. }
  64. parts := strings.Split(name, `\`)
  65. if len(parts) == 2 {
  66. if v, err := lookup(parts[1]); err == nil {
  67. return v, nil
  68. }
  69. }
  70. return "", errors.New("lookup failed")
  71. }