Home | History | Annotate | Download | only in tar
      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 // +build linux darwin dragonfly freebsd openbsd netbsd solaris
      6 
      7 package tar
      8 
      9 import (
     10 	"os"
     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 os.FileInfo, h *Header) 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 
     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.(string)
     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.(string)
     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 "linux":
     58 			// Copied from golang.org/x/sys/unix/dev_linux.go.
     59 			major := uint32((dev & 0x00000000000fff00) >> 8)
     60 			major |= uint32((dev & 0xfffff00000000000) >> 32)
     61 			minor := uint32((dev & 0x00000000000000ff) >> 0)
     62 			minor |= uint32((dev & 0x00000ffffff00000) >> 12)
     63 			h.Devmajor, h.Devminor = int64(major), int64(minor)
     64 		case "darwin":
     65 			// Copied from golang.org/x/sys/unix/dev_darwin.go.
     66 			major := uint32((dev >> 24) & 0xff)
     67 			minor := uint32(dev & 0xffffff)
     68 			h.Devmajor, h.Devminor = int64(major), int64(minor)
     69 		case "dragonfly":
     70 			// Copied from golang.org/x/sys/unix/dev_dragonfly.go.
     71 			major := uint32((dev >> 8) & 0xff)
     72 			minor := uint32(dev & 0xffff00ff)
     73 			h.Devmajor, h.Devminor = int64(major), int64(minor)
     74 		case "freebsd":
     75 			// Copied from golang.org/x/sys/unix/dev_freebsd.go.
     76 			major := uint32((dev >> 8) & 0xff)
     77 			minor := uint32(dev & 0xffff00ff)
     78 			h.Devmajor, h.Devminor = int64(major), int64(minor)
     79 		case "netbsd":
     80 			// Copied from golang.org/x/sys/unix/dev_netbsd.go.
     81 			major := uint32((dev & 0x000fff00) >> 8)
     82 			minor := uint32((dev & 0x000000ff) >> 0)
     83 			minor |= uint32((dev & 0xfff00000) >> 12)
     84 			h.Devmajor, h.Devminor = int64(major), int64(minor)
     85 		case "openbsd":
     86 			// Copied from golang.org/x/sys/unix/dev_openbsd.go.
     87 			major := uint32((dev & 0x0000ff00) >> 8)
     88 			minor := uint32((dev & 0x000000ff) >> 0)
     89 			minor |= uint32((dev & 0xffff0000) >> 8)
     90 			h.Devmajor, h.Devminor = int64(major), int64(minor)
     91 		default:
     92 			// TODO: Implement solaris (see https://golang.org/issue/8106)
     93 		}
     94 	}
     95 	return nil
     96 }
     97