Skip to content

Commit

Permalink
*: replace syscall with unix
Browse files Browse the repository at this point in the history
Some parts of the code required some more work than pure substitutions
as the unix interfaces expect a unix.Stat_t, so we couldn't just use
os.FileInfo's Sys() interface to get actual metadata.

Signed-off-by: Valentin Rothberg <vrothberg@suse.com>
[ small style cleanups ]
Signed-off-by: Aleksa Sarai <asarai@suse.de>
  • Loading branch information
vrothberg authored and cyphar committed Jul 20, 2017
1 parent 44f0f7d commit 80f787e
Show file tree
Hide file tree
Showing 16 changed files with 214 additions and 222 deletions.
8 changes: 4 additions & 4 deletions oci/cas/drivers/dir/dir_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import (
"io/ioutil"
"os"
"path/filepath"
"syscall"
"testing"

"github.com/openSUSE/umoci/oci/cas"
"github.com/pkg/errors"
"golang.org/x/net/context"
"golang.org/x/sys/unix"
)

// NOTE: These tests aren't really testing OCI-style manifests. It's all just
Expand All @@ -47,10 +47,10 @@ func readonly(t *testing.T, path string) {

t.Logf("mounting %s as readonly", path)

if err := syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_RDONLY, ""); err != nil {
if err := unix.Mount(path, path, "", unix.MS_BIND|unix.MS_RDONLY, ""); err != nil {
t.Fatalf("mount %s as ro: %s", path, err)
}
if err := syscall.Mount("none", path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil {
if err := unix.Mount("none", path, "", unix.MS_BIND|unix.MS_REMOUNT|unix.MS_RDONLY, ""); err != nil {
t.Fatalf("mount %s as ro: %s", path, err)
}
}
Expand All @@ -62,7 +62,7 @@ func readwrite(t *testing.T, path string) {
t.Skip()
}

if err := syscall.Unmount(path, syscall.MNT_DETACH); err != nil {
if err := unix.Unmount(path, unix.MNT_DETACH); err != nil {
t.Fatalf("unmount %s: %s", path, err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion oci/layer/tar_extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type tarExtractor struct {

// newTarExtractor creates a new tarExtractor.
func newTarExtractor(opt MapOptions) *tarExtractor {
var fsEval fseval.FsEval = fseval.DefaultFsEval
fsEval := fseval.DefaultFsEval
if opt.Rootless {
fsEval = fseval.RootlessFsEval
}
Expand Down
121 changes: 58 additions & 63 deletions oci/layer/tar_extract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ import (
"io/ioutil"
"os"
"path/filepath"
"syscall"
"testing"
"time"

rspec "github.com/opencontainers/runtime-spec/specs-go"
"golang.org/x/sys/unix"
)

// TODO: Test the parent directory metadata is kept the same when unpacking.
Expand Down Expand Up @@ -393,40 +393,34 @@ func TestUnpackHardlink(t *testing.T) {
}

// Now we have to check the inode numbers.
regFi, err := os.Lstat(filepath.Join(dir, regFile))
if err != nil {
var regFi, symFi, hardAFi, hardBFi unix.Stat_t

if err := unix.Lstat(filepath.Join(dir, regFile), &regFi); err != nil {
t.Fatalf("could not stat regular file: %s", err)
}
symFi, err := os.Lstat(filepath.Join(dir, symFile))
if err != nil {
if err := unix.Lstat(filepath.Join(dir, symFile), &symFi); err != nil {
t.Fatalf("could not stat symlink: %s", err)
}
hardAFi, err := os.Lstat(filepath.Join(dir, hardFileA))
if err != nil {
if err := unix.Lstat(filepath.Join(dir, hardFileA), &hardAFi); err != nil {
t.Fatalf("could not stat hardlinkA: %s", err)
}
hardBFi, err := os.Lstat(filepath.Join(dir, hardFileB))
if err != nil {
if err := unix.Lstat(filepath.Join(dir, hardFileB), &hardBFi); err != nil {
t.Fatalf("could not stat hardlinkB: %s", err)
}

// This test only runs on Linux anyway.
regIno := regFi.Sys().(*syscall.Stat_t).Ino
symIno := symFi.Sys().(*syscall.Stat_t).Ino
hardAIno := hardAFi.Sys().(*syscall.Stat_t).Ino
hardBIno := hardBFi.Sys().(*syscall.Stat_t).Ino

if regIno == symIno {
t.Errorf("regular and symlink have the same inode! ino=%d", regIno)
if regFi.Ino == symFi.Ino {
t.Errorf("regular and symlink have the same inode! ino=%d", regFi.Ino)
}
if hardAIno == hardBIno {
t.Errorf("both hardlinks have the same inode! ino=%d", hardAIno)
if hardAFi.Ino == hardBFi.Ino {
t.Errorf("both hardlinks have the same inode! ino=%d", hardAFi.Ino)
}
if hardAIno != regIno {
t.Errorf("hardlink to regular has a different inode: reg=%d hard=%d", regIno, hardAIno)
if hardAFi.Ino != regFi.Ino {
t.Errorf("hardlink to regular has a different inode: reg=%d hard=%d", regFi.Ino, hardAFi.Ino)
}
if hardBIno != symIno {
t.Errorf("hardlink to symlink has a different inode: sym=%d hard=%d", symIno, hardBIno)
if hardBFi.Ino != symFi.Ino {
t.Errorf("hardlink to symlink has a different inode: sym=%d hard=%d", symFi.Ino, hardBFi.Ino)
}

// Double-check readlink.
Expand All @@ -443,21 +437,17 @@ func TestUnpackHardlink(t *testing.T) {
}

// Make sure that uid and gid don't apply to hardlinks.
regUID := int(regFi.Sys().(*syscall.Stat_t).Uid)
if regUID != os.Getuid() {
t.Errorf("regular file: uid was changed by hardlink unpack: expected=%d got=%d", os.Getuid(), regUID)
if int(regFi.Uid) != os.Getuid() {
t.Errorf("regular file: uid was changed by hardlink unpack: expected=%d got=%d", os.Getuid(), regFi.Uid)
}
regGID := int(regFi.Sys().(*syscall.Stat_t).Gid)
if regGID != os.Getgid() {
t.Errorf("regular file: gid was changed by hardlink unpack: expected=%d got=%d", os.Getgid(), regGID)
if int(regFi.Gid) != os.Getgid() {
t.Errorf("regular file: gid was changed by hardlink unpack: expected=%d got=%d", os.Getgid(), regFi.Gid)
}
symUID := int(symFi.Sys().(*syscall.Stat_t).Uid)
if symUID != os.Getuid() {
t.Errorf("symlink: uid was changed by hardlink unpack: expected=%d got=%d", os.Getuid(), symUID)
if int(symFi.Uid) != os.Getuid() {
t.Errorf("symlink: uid was changed by hardlink unpack: expected=%d got=%d", os.Getuid(), symFi.Uid)
}
symGID := int(symFi.Sys().(*syscall.Stat_t).Gid)
if symGID != os.Getgid() {
t.Errorf("symlink: gid was changed by hardlink unpack: expected=%d got=%d", os.Getgid(), symGID)
if int(symFi.Gid) != os.Getgid() {
t.Errorf("symlink: gid was changed by hardlink unpack: expected=%d got=%d", os.Getgid(), symFi.Gid)
}
}

Expand Down Expand Up @@ -488,8 +478,9 @@ func TestUnpackEntryMap(t *testing.T) {
t.Logf("running with uid=%#v gid=%#v", test.uidMap, test.gidMap)

var (
hdr *tar.Header
hdrUID, hdrGID int
hdrUID, hdrGID, uUID, uGID int
hdr *tar.Header
fi unix.Stat_t

ctrValue = []byte("some content we won't check")
regFile = "regular"
Expand Down Expand Up @@ -519,16 +510,17 @@ func TestUnpackEntryMap(t *testing.T) {
if err := te.unpackEntry(dir, hdr, bytes.NewBuffer(ctrValue)); err != nil {
t.Fatalf("regfile: unexpected unpackEntry error: %s", err)
}
if fi, err := os.Lstat(filepath.Join(dir, hdr.Name)); err != nil {

if err := unix.Lstat(filepath.Join(dir, hdr.Name), &fi); err != nil {
t.Errorf("failed to lstat %s: %s", hdr.Name, err)
} else {
theUID := int(fi.Sys().(*syscall.Stat_t).Uid)
theGID := int(fi.Sys().(*syscall.Stat_t).Gid)
if theUID != int(test.uidMap.HostID)+hdrUID {
t.Errorf("file %s has the wrong uid mapping: got=%d expected=%d", hdr.Name, theUID, int(test.uidMap.HostID)+hdrUID)
uUID = int(fi.Uid)
uGID = int(fi.Gid)
if uUID != int(test.uidMap.HostID)+hdrUID {
t.Errorf("file %s has the wrong uid mapping: got=%d expected=%d", hdr.Name, uUID, int(test.uidMap.HostID)+hdrUID)
}
if theGID != int(test.gidMap.HostID)+hdrGID {
t.Errorf("file %s has the wrong gid mapping: got=%d expected=%d", hdr.Name, theGID, int(test.gidMap.HostID)+hdrGID)
if uGID != int(test.gidMap.HostID)+hdrGID {
t.Errorf("file %s has the wrong gid mapping: got=%d expected=%d", hdr.Name, uGID, int(test.gidMap.HostID)+hdrGID)
}
}

Expand All @@ -547,16 +539,17 @@ func TestUnpackEntryMap(t *testing.T) {
if err := te.unpackEntry(dir, hdr, bytes.NewBuffer(ctrValue)); err != nil {
t.Fatalf("regdir: unexpected unpackEntry error: %s", err)
}
if fi, err := os.Lstat(filepath.Join(dir, hdr.Name)); err != nil {

if err := unix.Lstat(filepath.Join(dir, hdr.Name), &fi); err != nil {
t.Errorf("failed to lstat %s: %s", hdr.Name, err)
} else {
theUID := int(fi.Sys().(*syscall.Stat_t).Uid)
theGID := int(fi.Sys().(*syscall.Stat_t).Gid)
if theUID != int(test.uidMap.HostID)+hdrUID {
t.Errorf("file %s has the wrong uid mapping: got=%d expected=%d", hdr.Name, theUID, int(test.uidMap.HostID)+hdrUID)
uUID = int(fi.Uid)
uGID = int(fi.Gid)
if uUID != int(test.uidMap.HostID)+hdrUID {
t.Errorf("file %s has the wrong uid mapping: got=%d expected=%d", hdr.Name, uUID, int(test.uidMap.HostID)+hdrUID)
}
if theGID != int(test.gidMap.HostID)+hdrGID {
t.Errorf("file %s has the wrong gid mapping: got=%d expected=%d", hdr.Name, theGID, int(test.gidMap.HostID)+hdrGID)
if uGID != int(test.gidMap.HostID)+hdrGID {
t.Errorf("file %s has the wrong gid mapping: got=%d expected=%d", hdr.Name, uGID, int(test.gidMap.HostID)+hdrGID)
}
}

Expand All @@ -575,16 +568,17 @@ func TestUnpackEntryMap(t *testing.T) {
if err := te.unpackEntry(dir, hdr, bytes.NewBuffer(ctrValue)); err != nil {
t.Fatalf("regdir: unexpected unpackEntry error: %s", err)
}
if fi, err := os.Lstat(filepath.Join(dir, hdr.Name)); err != nil {

if err := unix.Lstat(filepath.Join(dir, hdr.Name), &fi); err != nil {
t.Errorf("failed to lstat %s: %s", hdr.Name, err)
} else {
theUID := int(fi.Sys().(*syscall.Stat_t).Uid)
theGID := int(fi.Sys().(*syscall.Stat_t).Gid)
if theUID != int(test.uidMap.HostID)+hdrUID {
t.Errorf("file %s has the wrong uid mapping: got=%d expected=%d", hdr.Name, theUID, int(test.uidMap.HostID)+hdrUID)
uUID = int(fi.Uid)
uGID = int(fi.Gid)
if uUID != int(test.uidMap.HostID)+hdrUID {
t.Errorf("file %s has the wrong uid mapping: got=%d expected=%d", hdr.Name, uUID, int(test.uidMap.HostID)+hdrUID)
}
if theGID != int(test.gidMap.HostID)+hdrGID {
t.Errorf("file %s has the wrong gid mapping: got=%d expected=%d", hdr.Name, theGID, int(test.gidMap.HostID)+hdrGID)
if uGID != int(test.gidMap.HostID)+hdrGID {
t.Errorf("file %s has the wrong gid mapping: got=%d expected=%d", hdr.Name, uGID, int(test.gidMap.HostID)+hdrGID)
}
}

Expand All @@ -603,16 +597,17 @@ func TestUnpackEntryMap(t *testing.T) {
if err := te.unpackEntry(dir, hdr, bytes.NewBuffer(ctrValue)); err != nil {
t.Fatalf("regdir: unexpected unpackEntry error: %s", err)
}
if fi, err := os.Lstat(filepath.Join(dir, hdr.Name)); err != nil {

if err := unix.Lstat(filepath.Join(dir, hdr.Name), &fi); err != nil {
t.Errorf("failed to lstat %s: %s", hdr.Name, err)
} else {
theUID := int(fi.Sys().(*syscall.Stat_t).Uid)
theGID := int(fi.Sys().(*syscall.Stat_t).Gid)
if theUID != int(test.uidMap.HostID)+hdrUID {
t.Errorf("file %s has the wrong uid mapping: got=%d expected=%d", hdr.Name, theUID, int(test.uidMap.HostID)+hdrUID)
uUID = int(fi.Uid)
uGID = int(fi.Gid)
if uUID != int(test.uidMap.HostID)+hdrUID {
t.Errorf("file %s has the wrong uid mapping: got=%d expected=%d", hdr.Name, uUID, int(test.uidMap.HostID)+hdrUID)
}
if theGID != int(test.gidMap.HostID)+hdrGID {
t.Errorf("file %s has the wrong gid mapping: got=%d expected=%d", hdr.Name, theGID, int(test.gidMap.HostID)+hdrGID)
if uGID != int(test.gidMap.HostID)+hdrGID {
t.Errorf("file %s has the wrong gid mapping: got=%d expected=%d", hdr.Name, uGID, int(test.gidMap.HostID)+hdrGID)
}
}
}
Expand Down
23 changes: 9 additions & 14 deletions oci/layer/tar_generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ type tarGenerator struct {
// newTarGenerator creates a new tarGenerator using the provided writer as the
// output writer.
func newTarGenerator(w io.Writer, opt MapOptions) *tarGenerator {
var fsEval fseval.FsEval = fseval.DefaultFsEval
fsEval := fseval.DefaultFsEval
if opt.Rootless {
fsEval = fseval.RootlessFsEval
}
Expand Down Expand Up @@ -109,6 +109,7 @@ func normalise(rawPath string, isDir bool) (string, error) {
// hardlinks. This should be functionally equivalent to adding entries with GNU
// tar.
func (tg *tarGenerator) AddFile(name, path string) error {

fi, err := tg.fsEval.Lstat(path)
if err != nil {
return errors.Wrap(err, "add file lstat")
Expand Down Expand Up @@ -144,9 +145,11 @@ func (tg *tarGenerator) AddFile(name, path string) error {
// Different systems have different special things they need to set within
// a tar header. For example, device numbers are quite important to be set
// by us.
if err := updateHeader(hdr, fi); err != nil {
return errors.Wrap(err, "update hdr header")
statx, err := tg.fsEval.Lstatx(path)
if err != nil {
return errors.Wrapf(err, "lstatx %q", path)
}
updateHeader(hdr, statx)

// Set up xattrs externally to updateHeader because the function signature
// would look really dumb otherwise.
Expand Down Expand Up @@ -183,24 +186,16 @@ func (tg *tarGenerator) AddFile(name, path string) error {

// Not all systems have the concept of an inode, but I'm not in the mood to
// handle this in a way that makes anything other than GNU/Linux happy
// right now.
ino, err := getInode(fi)
if err != nil {
return errors.Wrap(err, "get inode")
}

// Handle hardlinks.
if oldpath, ok := tg.inodes[ino]; ok {
// right now. Handle hardlinks.
if oldpath, ok := tg.inodes[statx.Ino]; ok {
// We just hit a hardlink, so we just have to change the header.
hdr.Typeflag = tar.TypeLink
hdr.Linkname = oldpath
hdr.Size = 0
} else {
tg.inodes[ino] = name
tg.inodes[statx.Ino] = name
}

// XXX: What about xattrs.

// Apply any header mappings.
if err := mapHeader(hdr, tg.mapOptions); err != nil {
return errors.Wrap(err, "map header")
Expand Down
23 changes: 3 additions & 20 deletions oci/layer/tar_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@ package layer

import (
"archive/tar"
"fmt"
"os"
"syscall"

"github.com/openSUSE/umoci/pkg/system"
"golang.org/x/sys/unix"
)

// These values come from new_decode_dev() inside <linux/kdev_t.h>.
Expand All @@ -36,26 +34,11 @@ func minor(device uint64) uint64 {
return (device & 0xff) | ((device >> 12) & 0xfff00)
}

func updateHeader(hdr *tar.Header, fi os.FileInfo) error {
s, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return fmt.Errorf("failed to cast fileinfo to *syscall.stat_t")
}

func updateHeader(hdr *tar.Header, s unix.Stat_t) {
// Currently the Go stdlib doesn't fill in the major/minor numbers of
// devices, so we have to do it manually.
if s.Mode&syscall.S_IFBLK == syscall.S_IFBLK || s.Mode&syscall.S_IFCHR == syscall.S_IFCHR {
if s.Mode&unix.S_IFBLK == unix.S_IFBLK || s.Mode&unix.S_IFCHR == unix.S_IFCHR {
hdr.Devmajor = int64(system.Majordev(system.Dev_t(s.Rdev)))
hdr.Devminor = int64(system.Minordev(system.Dev_t(s.Rdev)))
}

return nil
}

func getInode(fi os.FileInfo) (uint64, error) {
s, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return 0, fmt.Errorf("failed to cast fileinfo to *syscall.stat_t")
}
return s.Ino, nil
}
4 changes: 4 additions & 0 deletions pkg/fseval/fseval.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

"github.com/openSUSE/umoci/pkg/system"
"github.com/vbatts/go-mtree"
"golang.org/x/sys/unix"
)

// Ensure that mtree.FsEval is implemented by FsEval.
Expand All @@ -45,6 +46,9 @@ type FsEval interface {
// Lstat is equivalent to os.Lstat.
Lstat(path string) (os.FileInfo, error)

// Lstatx is equivalent to unix.Lstat.
Lstatx(path string) (unix.Stat_t, error)

// Readlink is equivalent to os.Readlink.
Readlink(path string) (string, error)

Expand Down
7 changes: 7 additions & 0 deletions pkg/fseval/fseval_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ func (fs osFsEval) Lstat(path string) (os.FileInfo, error) {
return os.Lstat(path)
}

// Lstatx is equivalent to unix.Lstat.
func (fs osFsEval) Lstatx(path string) (unix.Stat_t, error) {
var s unix.Stat_t
err := unix.Lstat(path, &s)
return s, err
}

// Readlink is equivalent to os.Readlink.
func (fs osFsEval) Readlink(path string) (string, error) {
return os.Readlink(path)
Expand Down
Loading

0 comments on commit 80f787e

Please sign in to comment.