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