github.com/cdoern/storage@v1.12.13/drivers/chown_unix.go (about)

     1  // +build !windows
     2  
     3  package graphdriver
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"syscall"
     9  
    10  	"github.com/containers/storage/pkg/idtools"
    11  	"github.com/containers/storage/pkg/system"
    12  )
    13  
    14  func platformLChown(path string, info os.FileInfo, toHost, toContainer *idtools.IDMappings) error {
    15  	sysinfo := info.Sys()
    16  	if st, ok := sysinfo.(*syscall.Stat_t); ok {
    17  		// Map an on-disk UID/GID pair from host to container
    18  		// using the first map, then back to the host using the
    19  		// second map.  Skip that first step if they're 0, to
    20  		// compensate for cases where a parent layer should
    21  		// have had a mapped value, but didn't.
    22  		uid, gid := int(st.Uid), int(st.Gid)
    23  		if toContainer != nil {
    24  			pair := idtools.IDPair{
    25  				UID: uid,
    26  				GID: gid,
    27  			}
    28  			mappedUid, mappedGid, err := toContainer.ToContainer(pair)
    29  			if err != nil {
    30  				if (uid != 0) || (gid != 0) {
    31  					return fmt.Errorf("error mapping host ID pair %#v for %q to container: %v", pair, path, err)
    32  				}
    33  				mappedUid, mappedGid = uid, gid
    34  			}
    35  			uid, gid = mappedUid, mappedGid
    36  		}
    37  		if toHost != nil {
    38  			pair := idtools.IDPair{
    39  				UID: uid,
    40  				GID: gid,
    41  			}
    42  			mappedPair, err := toHost.ToHost(pair)
    43  			if err != nil {
    44  				return fmt.Errorf("error mapping container ID pair %#v for %q to host: %v", pair, path, err)
    45  			}
    46  			uid, gid = mappedPair.UID, mappedPair.GID
    47  		}
    48  		if uid != int(st.Uid) || gid != int(st.Gid) {
    49  			stat, err := os.Lstat(path)
    50  			if err != nil {
    51  				return fmt.Errorf("%s: lstat(%q): %v", os.Args[0], path, err)
    52  			}
    53  			cap, err := system.Lgetxattr(path, "security.capability")
    54  			if err != nil && err != system.ErrNotSupportedPlatform {
    55  				return fmt.Errorf("%s: Lgetxattr(%q): %v", os.Args[0], path, err)
    56  			}
    57  
    58  			// Make the change.
    59  			if err := syscall.Lchown(path, uid, gid); err != nil {
    60  				return fmt.Errorf("%s: chown(%q): %v", os.Args[0], path, err)
    61  			}
    62  			// Restore the SUID and SGID bits if they were originally set.
    63  			if (stat.Mode()&os.ModeSymlink == 0) && stat.Mode()&(os.ModeSetuid|os.ModeSetgid) != 0 {
    64  				if err := os.Chmod(path, stat.Mode()); err != nil {
    65  					return fmt.Errorf("%s: chmod(%q): %v", os.Args[0], path, err)
    66  				}
    67  			}
    68  			if cap != nil {
    69  				if err := system.Lsetxattr(path, "security.capability", cap, 0); err != nil {
    70  					return fmt.Errorf("%s: Lsetxattr(%q): %v", os.Args[0], path, err)
    71  				}
    72  			}
    73  
    74  		}
    75  	}
    76  	return nil
    77  }