stat_unix.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // Copyright 2012 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build linux darwin dragonfly freebsd openbsd netbsd solaris
  5. package tar
  6. import (
  7. "os"
  8. "os/user"
  9. "runtime"
  10. "strconv"
  11. "sync"
  12. "syscall"
  13. )
  14. func init() {
  15. sysStat = statUnix
  16. }
  17. // userMap and groupMap caches UID and GID lookups for performance reasons.
  18. // The downside is that renaming uname or gname by the OS never takes effect.
  19. var userMap, groupMap sync.Map // map[int]string
  20. func statUnix(fi os.FileInfo, h *Header) error {
  21. sys, ok := fi.Sys().(*syscall.Stat_t)
  22. if !ok {
  23. return nil
  24. }
  25. h.Uid = int(sys.Uid)
  26. h.Gid = int(sys.Gid)
  27. // Best effort at populating Uname and Gname.
  28. // The os/user functions may fail for any number of reasons
  29. // (not implemented on that platform, cgo not enabled, etc).
  30. if u, ok := userMap.Load(h.Uid); ok {
  31. h.Uname = u.(string)
  32. } else if u, err := user.LookupId(strconv.Itoa(h.Uid)); err == nil {
  33. h.Uname = u.Username
  34. userMap.Store(h.Uid, h.Uname)
  35. }
  36. if g, ok := groupMap.Load(h.Gid); ok {
  37. h.Gname = g.(string)
  38. } else if g, err := user.LookupGroupId(strconv.Itoa(h.Gid)); err == nil {
  39. h.Gname = g.Name
  40. groupMap.Store(h.Gid, h.Gname)
  41. }
  42. h.AccessTime = statAtime(sys)
  43. h.ChangeTime = statCtime(sys)
  44. // Best effort at populating Devmajor and Devminor.
  45. if h.Typeflag == TypeChar || h.Typeflag == TypeBlock {
  46. dev := uint64(sys.Rdev) // May be int32 or uint32
  47. switch runtime.GOOS {
  48. case "linux":
  49. // Copied from golang.org/x/sys/unix/dev_linux.go.
  50. major := uint32((dev & 0x00000000000fff00) >> 8)
  51. major |= uint32((dev & 0xfffff00000000000) >> 32)
  52. minor := uint32((dev & 0x00000000000000ff) >> 0)
  53. minor |= uint32((dev & 0x00000ffffff00000) >> 12)
  54. h.Devmajor, h.Devminor = int64(major), int64(minor)
  55. case "darwin":
  56. // Copied from golang.org/x/sys/unix/dev_darwin.go.
  57. major := uint32((dev >> 24) & 0xff)
  58. minor := uint32(dev & 0xffffff)
  59. h.Devmajor, h.Devminor = int64(major), int64(minor)
  60. case "dragonfly":
  61. // Copied from golang.org/x/sys/unix/dev_dragonfly.go.
  62. major := uint32((dev >> 8) & 0xff)
  63. minor := uint32(dev & 0xffff00ff)
  64. h.Devmajor, h.Devminor = int64(major), int64(minor)
  65. case "freebsd":
  66. // Copied from golang.org/x/sys/unix/dev_freebsd.go.
  67. major := uint32((dev >> 8) & 0xff)
  68. minor := uint32(dev & 0xffff00ff)
  69. h.Devmajor, h.Devminor = int64(major), int64(minor)
  70. case "netbsd":
  71. // Copied from golang.org/x/sys/unix/dev_netbsd.go.
  72. major := uint32((dev & 0x000fff00) >> 8)
  73. minor := uint32((dev & 0x000000ff) >> 0)
  74. minor |= uint32((dev & 0xfff00000) >> 12)
  75. h.Devmajor, h.Devminor = int64(major), int64(minor)
  76. case "openbsd":
  77. // Copied from golang.org/x/sys/unix/dev_openbsd.go.
  78. major := uint32((dev & 0x0000ff00) >> 8)
  79. minor := uint32((dev & 0x000000ff) >> 0)
  80. minor |= uint32((dev & 0xffff0000) >> 8)
  81. h.Devmajor, h.Devminor = int64(major), int64(minor)
  82. default:
  83. // TODO: Implement solaris (see https://golang.org/issue/8106)
  84. }
  85. }
  86. return nil
  87. }