stat_unix.mx raw

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