Windows: Updates Windows Vendoring
Updates windows dependent libraries for vendoing.
This commit is contained in:
1263
vendor/github.com/Microsoft/hcsshim/ext4/internal/compactext4/compact.go
generated
vendored
Normal file
1263
vendor/github.com/Microsoft/hcsshim/ext4/internal/compactext4/compact.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
355
vendor/github.com/Microsoft/hcsshim/ext4/internal/compactext4/compact_test.go
generated
vendored
Normal file
355
vendor/github.com/Microsoft/hcsshim/ext4/internal/compactext4/compact_test.go
generated
vendored
Normal file
@ -0,0 +1,355 @@
|
||||
package compactext4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Microsoft/hcsshim/ext4/internal/format"
|
||||
)
|
||||
|
||||
type testFile struct {
|
||||
Path string
|
||||
File *File
|
||||
Data []byte
|
||||
DataSize int64
|
||||
Link string
|
||||
ExpectError bool
|
||||
}
|
||||
|
||||
var (
|
||||
data []byte
|
||||
name string
|
||||
)
|
||||
|
||||
func init() {
|
||||
data = make([]byte, blockSize*2)
|
||||
for i := range data {
|
||||
data[i] = uint8(i)
|
||||
}
|
||||
|
||||
nameb := make([]byte, 300)
|
||||
for i := range nameb {
|
||||
nameb[i] = byte('0' + i%10)
|
||||
}
|
||||
name = string(nameb)
|
||||
}
|
||||
|
||||
type largeData struct {
|
||||
pos int64
|
||||
}
|
||||
|
||||
func (d *largeData) Read(b []byte) (int, error) {
|
||||
p := d.pos
|
||||
var pb [8]byte
|
||||
for i := range b {
|
||||
binary.LittleEndian.PutUint64(pb[:], uint64(p+int64(i)))
|
||||
b[i] = pb[i%8]
|
||||
}
|
||||
p += int64(len(b))
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (tf *testFile) Reader() io.Reader {
|
||||
if tf.DataSize != 0 {
|
||||
return io.LimitReader(&largeData{}, tf.DataSize)
|
||||
}
|
||||
return bytes.NewReader(tf.Data)
|
||||
}
|
||||
|
||||
func createTestFile(t *testing.T, w *Writer, tf testFile) {
|
||||
var err error
|
||||
if tf.File != nil {
|
||||
tf.File.Size = int64(len(tf.Data))
|
||||
if tf.File.Size == 0 {
|
||||
tf.File.Size = tf.DataSize
|
||||
}
|
||||
err = w.Create(tf.Path, tf.File)
|
||||
} else {
|
||||
err = w.Link(tf.Link, tf.Path)
|
||||
}
|
||||
if tf.ExpectError && err == nil {
|
||||
t.Errorf("%s: expected error", tf.Path)
|
||||
} else if !tf.ExpectError && err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
_, err := io.Copy(w, tf.Reader())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func expectedMode(f *File) uint16 {
|
||||
switch f.Mode & format.TypeMask {
|
||||
case 0:
|
||||
return f.Mode | S_IFREG
|
||||
case S_IFLNK:
|
||||
return f.Mode | 0777
|
||||
default:
|
||||
return f.Mode
|
||||
}
|
||||
}
|
||||
|
||||
func expectedSize(f *File) int64 {
|
||||
switch f.Mode & format.TypeMask {
|
||||
case 0, S_IFREG:
|
||||
return f.Size
|
||||
case S_IFLNK:
|
||||
return int64(len(f.Linkname))
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func xattrsEqual(x1, x2 map[string][]byte) bool {
|
||||
if len(x1) != len(x2) {
|
||||
return false
|
||||
}
|
||||
for name, value := range x1 {
|
||||
if !bytes.Equal(x2[name], value) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func fileEqual(f1, f2 *File) bool {
|
||||
return f1.Linkname == f2.Linkname &&
|
||||
expectedSize(f1) == expectedSize(f2) &&
|
||||
expectedMode(f1) == expectedMode(f2) &&
|
||||
f1.Uid == f2.Uid &&
|
||||
f1.Gid == f2.Gid &&
|
||||
f1.Atime.Equal(f2.Atime) &&
|
||||
f1.Ctime.Equal(f2.Ctime) &&
|
||||
f1.Mtime.Equal(f2.Mtime) &&
|
||||
f1.Crtime.Equal(f2.Crtime) &&
|
||||
f1.Devmajor == f2.Devmajor &&
|
||||
f1.Devminor == f2.Devminor &&
|
||||
xattrsEqual(f1.Xattrs, f2.Xattrs)
|
||||
}
|
||||
|
||||
func runTestsOnFiles(t *testing.T, testFiles []testFile, opts ...Option) {
|
||||
image := "testfs.img"
|
||||
imagef, err := os.Create(image)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(image)
|
||||
defer imagef.Close()
|
||||
|
||||
w := NewWriter(imagef, opts...)
|
||||
for _, tf := range testFiles {
|
||||
createTestFile(t, w, tf)
|
||||
if !tf.ExpectError && tf.File != nil {
|
||||
f, err := w.Stat(tf.Path)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "cannot retrieve") {
|
||||
t.Error(err)
|
||||
}
|
||||
} else if !fileEqual(f, tf.File) {
|
||||
t.Errorf("%s: stat mismatch: %#v %#v", tf.Path, tf.File, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if t.Failed() {
|
||||
return
|
||||
}
|
||||
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fsck(t, image)
|
||||
|
||||
mountPath := "testmnt"
|
||||
|
||||
if mountImage(t, image, mountPath) {
|
||||
defer unmountImage(t, mountPath)
|
||||
validated := make(map[string]*testFile)
|
||||
for i := range testFiles {
|
||||
tf := testFiles[len(testFiles)-i-1]
|
||||
if validated[tf.Link] != nil {
|
||||
// The link target was subsequently replaced. Find the
|
||||
// earlier instance.
|
||||
for j := range testFiles[:len(testFiles)-i-1] {
|
||||
otf := testFiles[j]
|
||||
if otf.Path == tf.Link && !otf.ExpectError {
|
||||
tf = otf
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !tf.ExpectError && validated[tf.Path] == nil {
|
||||
verifyTestFile(t, mountPath, tf)
|
||||
validated[tf.Path] = &tf
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasic(t *testing.T) {
|
||||
now := time.Now()
|
||||
testFiles := []testFile{
|
||||
{Path: "empty", File: &File{Mode: 0644}},
|
||||
{Path: "small", File: &File{Mode: 0644}, Data: data[:40]},
|
||||
{Path: "time", File: &File{Atime: now, Ctime: now.Add(time.Second), Mtime: now.Add(time.Hour)}},
|
||||
{Path: "block_1", File: &File{Mode: 0644}, Data: data[:blockSize]},
|
||||
{Path: "block_2", File: &File{Mode: 0644}, Data: data[:blockSize*2]},
|
||||
{Path: "symlink", File: &File{Linkname: "block_1", Mode: format.S_IFLNK}},
|
||||
{Path: "symlink_59", File: &File{Linkname: name[:59], Mode: format.S_IFLNK}},
|
||||
{Path: "symlink_60", File: &File{Linkname: name[:60], Mode: format.S_IFLNK}},
|
||||
{Path: "symlink_120", File: &File{Linkname: name[:120], Mode: format.S_IFLNK}},
|
||||
{Path: "symlink_300", File: &File{Linkname: name[:300], Mode: format.S_IFLNK}},
|
||||
{Path: "dir", File: &File{Mode: format.S_IFDIR | 0755}},
|
||||
{Path: "dir/fifo", File: &File{Mode: format.S_IFIFO}},
|
||||
{Path: "dir/sock", File: &File{Mode: format.S_IFSOCK}},
|
||||
{Path: "dir/blk", File: &File{Mode: format.S_IFBLK, Devmajor: 0x5678, Devminor: 0x1234}},
|
||||
{Path: "dir/chr", File: &File{Mode: format.S_IFCHR, Devmajor: 0x5678, Devminor: 0x1234}},
|
||||
{Path: "dir/hard_link", Link: "small"},
|
||||
}
|
||||
|
||||
runTestsOnFiles(t, testFiles)
|
||||
}
|
||||
|
||||
func TestLargeDirectory(t *testing.T) {
|
||||
testFiles := []testFile{
|
||||
{Path: "bigdir", File: &File{Mode: format.S_IFDIR | 0755}},
|
||||
}
|
||||
for i := 0; i < 50000; i++ {
|
||||
testFiles = append(testFiles, testFile{
|
||||
Path: fmt.Sprintf("bigdir/%d", i), File: &File{Mode: 0644},
|
||||
})
|
||||
}
|
||||
|
||||
runTestsOnFiles(t, testFiles)
|
||||
}
|
||||
|
||||
func TestInlineData(t *testing.T) {
|
||||
testFiles := []testFile{
|
||||
{Path: "inline_30", File: &File{Mode: 0644}, Data: data[:30]},
|
||||
{Path: "inline_60", File: &File{Mode: 0644}, Data: data[:60]},
|
||||
{Path: "inline_120", File: &File{Mode: 0644}, Data: data[:120]},
|
||||
{Path: "inline_full", File: &File{Mode: 0644}, Data: data[:inlineDataSize]},
|
||||
{Path: "block_min", File: &File{Mode: 0644}, Data: data[:inlineDataSize+1]},
|
||||
}
|
||||
|
||||
runTestsOnFiles(t, testFiles, InlineData)
|
||||
}
|
||||
|
||||
func TestXattrs(t *testing.T) {
|
||||
testFiles := []testFile{
|
||||
{Path: "withsmallxattrs",
|
||||
File: &File{
|
||||
Mode: format.S_IFREG | 0644,
|
||||
Xattrs: map[string][]byte{
|
||||
"user.foo": []byte("test"),
|
||||
"user.bar": []byte("test2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{Path: "withlargexattrs",
|
||||
File: &File{
|
||||
Mode: format.S_IFREG | 0644,
|
||||
Xattrs: map[string][]byte{
|
||||
"user.foo": data[:100],
|
||||
"user.bar": data[:50],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
runTestsOnFiles(t, testFiles)
|
||||
}
|
||||
|
||||
func TestReplace(t *testing.T) {
|
||||
testFiles := []testFile{
|
||||
{Path: "lost+found", ExpectError: true, File: &File{}}, // can't change type
|
||||
{Path: "lost+found", File: &File{Mode: format.S_IFDIR | 0777}},
|
||||
|
||||
{Path: "dir", File: &File{Mode: format.S_IFDIR | 0777}},
|
||||
{Path: "dir/file", File: &File{}},
|
||||
{Path: "dir", File: &File{Mode: format.S_IFDIR | 0700}},
|
||||
|
||||
{Path: "file", File: &File{}},
|
||||
{Path: "file", File: &File{Mode: 0600}},
|
||||
{Path: "file2", File: &File{}},
|
||||
{Path: "link", Link: "file2"},
|
||||
{Path: "file2", File: &File{Mode: 0600}},
|
||||
|
||||
{Path: "nolinks", File: &File{}},
|
||||
{Path: "nolinks", ExpectError: true, Link: "file"}, // would orphan nolinks
|
||||
|
||||
{Path: "onelink", File: &File{}},
|
||||
{Path: "onelink2", Link: "onelink"},
|
||||
{Path: "onelink", Link: "file"},
|
||||
|
||||
{Path: "", ExpectError: true, File: &File{}},
|
||||
{Path: "", ExpectError: true, Link: "file"},
|
||||
{Path: "", File: &File{Mode: format.S_IFDIR | 0777}},
|
||||
|
||||
{Path: "smallxattr", File: &File{Xattrs: map[string][]byte{"user.foo": data[:4]}}},
|
||||
{Path: "smallxattr", File: &File{Xattrs: map[string][]byte{"user.foo": data[:8]}}},
|
||||
|
||||
{Path: "smallxattr_delete", File: &File{Xattrs: map[string][]byte{"user.foo": data[:4]}}},
|
||||
{Path: "smallxattr_delete", File: &File{}},
|
||||
|
||||
{Path: "largexattr", File: &File{Xattrs: map[string][]byte{"user.small": data[:8], "user.foo": data[:200]}}},
|
||||
{Path: "largexattr", File: &File{Xattrs: map[string][]byte{"user.small": data[:12], "user.foo": data[:400]}}},
|
||||
|
||||
{Path: "largexattr", File: &File{Xattrs: map[string][]byte{"user.foo": data[:200]}}},
|
||||
{Path: "largexattr_delete", File: &File{}},
|
||||
}
|
||||
runTestsOnFiles(t, testFiles)
|
||||
}
|
||||
|
||||
func TestTime(t *testing.T) {
|
||||
now := time.Now()
|
||||
now2 := fsTimeToTime(timeToFsTime(now))
|
||||
if now.UnixNano() != now2.UnixNano() {
|
||||
t.Fatalf("%s != %s", now, now2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLargeFile(t *testing.T) {
|
||||
testFiles := []testFile{
|
||||
{Path: "small", File: &File{}, DataSize: 1024 * 1024}, // can't change type
|
||||
{Path: "medium", File: &File{}, DataSize: 200 * 1024 * 1024}, // can't change type
|
||||
{Path: "large", File: &File{}, DataSize: 600 * 1024 * 1024}, // can't change type
|
||||
}
|
||||
runTestsOnFiles(t, testFiles)
|
||||
}
|
||||
|
||||
func TestFileLinkLimit(t *testing.T) {
|
||||
testFiles := []testFile{
|
||||
{Path: "file", File: &File{}},
|
||||
}
|
||||
for i := 0; i < format.MaxLinks; i++ {
|
||||
testFiles = append(testFiles, testFile{Path: fmt.Sprintf("link%d", i), Link: "file"})
|
||||
}
|
||||
testFiles[len(testFiles)-1].ExpectError = true
|
||||
runTestsOnFiles(t, testFiles)
|
||||
}
|
||||
|
||||
func TestDirLinkLimit(t *testing.T) {
|
||||
testFiles := []testFile{
|
||||
{Path: "dir", File: &File{Mode: S_IFDIR}},
|
||||
}
|
||||
for i := 0; i < format.MaxLinks-1; i++ {
|
||||
testFiles = append(testFiles, testFile{Path: fmt.Sprintf("dir/%d", i), File: &File{Mode: S_IFDIR}})
|
||||
}
|
||||
testFiles[len(testFiles)-1].ExpectError = true
|
||||
runTestsOnFiles(t, testFiles)
|
||||
}
|
||||
|
||||
func TestLargeDisk(t *testing.T) {
|
||||
testFiles := []testFile{
|
||||
{Path: "file", File: &File{}},
|
||||
}
|
||||
runTestsOnFiles(t, testFiles, MaximumDiskSize(maxMaxDiskSize))
|
||||
}
|
248
vendor/github.com/Microsoft/hcsshim/ext4/internal/compactext4/verify_linux_test.go
generated
vendored
Normal file
248
vendor/github.com/Microsoft/hcsshim/ext4/internal/compactext4/verify_linux_test.go
generated
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
package compactext4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Microsoft/hcsshim/ext4/internal/format"
|
||||
)
|
||||
|
||||
func timeEqual(ts syscall.Timespec, t time.Time) bool {
|
||||
sec, nsec := t.Unix(), t.Nanosecond()
|
||||
if t.IsZero() {
|
||||
sec, nsec = 0, 0
|
||||
}
|
||||
return ts.Sec == sec && int(ts.Nsec) == nsec
|
||||
}
|
||||
|
||||
func expectedDevice(f *File) uint64 {
|
||||
return uint64(f.Devminor&0xff | f.Devmajor<<8 | (f.Devminor&0xffffff00)<<12)
|
||||
}
|
||||
|
||||
func llistxattr(path string, b []byte) (int, error) {
|
||||
pathp := syscall.StringBytePtr(path)
|
||||
var p unsafe.Pointer
|
||||
if len(b) > 0 {
|
||||
p = unsafe.Pointer(&b[0])
|
||||
}
|
||||
r, _, e := syscall.Syscall(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(pathp)), uintptr(p), uintptr(len(b)))
|
||||
if e != 0 {
|
||||
return 0, &os.PathError{Path: path, Op: "llistxattr", Err: syscall.Errno(e)}
|
||||
}
|
||||
return int(r), nil
|
||||
}
|
||||
|
||||
func lgetxattr(path string, name string, b []byte) (int, error) {
|
||||
pathp := syscall.StringBytePtr(path)
|
||||
namep := syscall.StringBytePtr(name)
|
||||
var p unsafe.Pointer
|
||||
if len(b) > 0 {
|
||||
p = unsafe.Pointer(&b[0])
|
||||
}
|
||||
r, _, e := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathp)), uintptr(unsafe.Pointer(namep)), uintptr(p), uintptr(len(b)), 0, 0)
|
||||
if e != 0 {
|
||||
return 0, &os.PathError{Path: path, Op: "lgetxattr", Err: syscall.Errno(e)}
|
||||
}
|
||||
return int(r), nil
|
||||
}
|
||||
|
||||
func readXattrs(path string) (map[string][]byte, error) {
|
||||
xattrs := make(map[string][]byte)
|
||||
var buf [4096]byte
|
||||
var buf2 [4096]byte
|
||||
b := buf[:]
|
||||
n, err := llistxattr(path, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = b[:n]
|
||||
for len(b) != 0 {
|
||||
nn := bytes.IndexByte(b, 0)
|
||||
name := string(b[:nn])
|
||||
b = b[nn+1:]
|
||||
vn, err := lgetxattr(path, name, buf2[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value := buf2[:vn]
|
||||
xattrs[name] = value
|
||||
}
|
||||
return xattrs, nil
|
||||
}
|
||||
|
||||
func streamEqual(r1, r2 io.Reader) (bool, error) {
|
||||
var b [4096]byte
|
||||
var b2 [4096]byte
|
||||
for {
|
||||
n, err := r1.Read(b[:])
|
||||
if n == 0 {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
_, err = io.ReadFull(r2, b2[:n])
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
return false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !bytes.Equal(b[n:], b2[n:]) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
// Check the tail of r2
|
||||
_, err := r2.Read(b[:1])
|
||||
if err == nil {
|
||||
return false, nil
|
||||
}
|
||||
if err != io.EOF {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func verifyTestFile(t *testing.T, mountPath string, tf testFile) {
|
||||
name := path.Join(mountPath, tf.Path)
|
||||
fi, err := os.Lstat(name)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
st := fi.Sys().(*syscall.Stat_t)
|
||||
if tf.File != nil {
|
||||
if st.Mode != uint32(expectedMode(tf.File)) ||
|
||||
st.Uid != tf.File.Uid ||
|
||||
st.Gid != tf.File.Gid ||
|
||||
(!fi.IsDir() && st.Size != expectedSize(tf.File)) ||
|
||||
st.Rdev != expectedDevice(tf.File) ||
|
||||
!timeEqual(st.Atim, tf.File.Atime) ||
|
||||
!timeEqual(st.Mtim, tf.File.Mtime) ||
|
||||
!timeEqual(st.Ctim, tf.File.Ctime) {
|
||||
|
||||
t.Errorf("%s: stat mismatch, expected: %#v got: %#v", tf.Path, tf.File, st)
|
||||
}
|
||||
|
||||
xattrs, err := readXattrs(name)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else if !xattrsEqual(xattrs, tf.File.Xattrs) {
|
||||
t.Errorf("%s: xattr mismatch, expected: %#v got: %#v", tf.Path, tf.File.Xattrs, xattrs)
|
||||
}
|
||||
|
||||
switch tf.File.Mode & format.TypeMask {
|
||||
case S_IFREG:
|
||||
if f, err := os.Open(name); err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
same, err := streamEqual(f, tf.Reader())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else if !same {
|
||||
t.Errorf("%s: data mismatch", tf.Path)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
case S_IFLNK:
|
||||
if link, err := os.Readlink(name); err != nil {
|
||||
t.Error(err)
|
||||
} else if link != tf.File.Linkname {
|
||||
t.Errorf("%s: link mismatch, expected: %s got: %s", tf.Path, tf.File.Linkname, link)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lfi, err := os.Lstat(path.Join(mountPath, tf.Link))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
lst := lfi.Sys().(*syscall.Stat_t)
|
||||
if lst.Ino != st.Ino {
|
||||
t.Errorf("%s: hard link mismatch with %s, expected inode: %d got inode: %d", tf.Path, tf.Link, lst.Ino, st.Ino)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type capHeader struct {
|
||||
version uint32
|
||||
pid int
|
||||
}
|
||||
|
||||
type capData struct {
|
||||
effective uint32
|
||||
permitted uint32
|
||||
inheritable uint32
|
||||
}
|
||||
|
||||
const CAP_SYS_ADMIN = 21
|
||||
|
||||
type caps struct {
|
||||
hdr capHeader
|
||||
data [2]capData
|
||||
}
|
||||
|
||||
func getCaps() (caps, error) {
|
||||
var c caps
|
||||
|
||||
// Get capability version
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(nil)), 0); errno != 0 {
|
||||
return c, fmt.Errorf("SYS_CAPGET: %v", errno)
|
||||
}
|
||||
|
||||
// Get current capabilities
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(&c.data[0])), 0); errno != 0 {
|
||||
return c, fmt.Errorf("SYS_CAPGET: %v", errno)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func mountImage(t *testing.T, image string, mountPath string) bool {
|
||||
caps, err := getCaps()
|
||||
if err != nil || caps.data[0].effective&(1<<uint(CAP_SYS_ADMIN)) == 0 {
|
||||
t.Log("cannot mount to run verification tests without CAP_SYS_ADMIN")
|
||||
return false
|
||||
}
|
||||
|
||||
err = os.MkdirAll(mountPath, 0777)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
out, err := exec.Command("mount", "-o", "loop,ro", "-t", "ext4", image, mountPath).CombinedOutput()
|
||||
t.Logf("%s", out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func unmountImage(t *testing.T, mountPath string) {
|
||||
out, err := exec.Command("umount", mountPath).CombinedOutput()
|
||||
t.Logf("%s", out)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
}
|
||||
|
||||
func fsck(t *testing.T, image string) {
|
||||
cmd := exec.Command("e2fsck", "-v", "-f", "-n", image)
|
||||
out, err := cmd.CombinedOutput()
|
||||
t.Logf("%s", out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
18
vendor/github.com/Microsoft/hcsshim/ext4/internal/compactext4/verify_test.go
generated
vendored
Normal file
18
vendor/github.com/Microsoft/hcsshim/ext4/internal/compactext4/verify_test.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// +build !linux
|
||||
|
||||
package compactext4
|
||||
|
||||
import "testing"
|
||||
|
||||
func verifyTestFile(t *testing.T, mountPath string, tf testFile) {
|
||||
}
|
||||
|
||||
func mountImage(t *testing.T, image string, mountPath string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func unmountImage(t *testing.T, mountPath string) {
|
||||
}
|
||||
|
||||
func fsck(t *testing.T, image string) {
|
||||
}
|
411
vendor/github.com/Microsoft/hcsshim/ext4/internal/format/format.go
generated
vendored
Normal file
411
vendor/github.com/Microsoft/hcsshim/ext4/internal/format/format.go
generated
vendored
Normal file
@ -0,0 +1,411 @@
|
||||
package format
|
||||
|
||||
type SuperBlock struct {
|
||||
InodesCount uint32
|
||||
BlocksCountLow uint32
|
||||
RootBlocksCountLow uint32
|
||||
FreeBlocksCountLow uint32
|
||||
FreeInodesCount uint32
|
||||
FirstDataBlock uint32
|
||||
LogBlockSize uint32
|
||||
LogClusterSize uint32
|
||||
BlocksPerGroup uint32
|
||||
ClustersPerGroup uint32
|
||||
InodesPerGroup uint32
|
||||
Mtime uint32
|
||||
Wtime uint32
|
||||
MountCount uint16
|
||||
MaxMountCount uint16
|
||||
Magic uint16
|
||||
State uint16
|
||||
Errors uint16
|
||||
MinorRevisionLevel uint16
|
||||
LastCheck uint32
|
||||
CheckInterval uint32
|
||||
CreatorOS uint32
|
||||
RevisionLevel uint32
|
||||
DefaultReservedUid uint16
|
||||
DefaultReservedGid uint16
|
||||
FirstInode uint32
|
||||
InodeSize uint16
|
||||
BlockGroupNr uint16
|
||||
FeatureCompat CompatFeature
|
||||
FeatureIncompat IncompatFeature
|
||||
FeatureRoCompat RoCompatFeature
|
||||
UUID [16]uint8
|
||||
VolumeName [16]byte
|
||||
LastMounted [64]byte
|
||||
AlgorithmUsageBitmap uint32
|
||||
PreallocBlocks uint8
|
||||
PreallocDirBlocks uint8
|
||||
ReservedGdtBlocks uint16
|
||||
JournalUUID [16]uint8
|
||||
JournalInum uint32
|
||||
JournalDev uint32
|
||||
LastOrphan uint32
|
||||
HashSeed [4]uint32
|
||||
DefHashVersion uint8
|
||||
JournalBackupType uint8
|
||||
DescSize uint16
|
||||
DefaultMountOpts uint32
|
||||
FirstMetaBg uint32
|
||||
MkfsTime uint32
|
||||
JournalBlocks [17]uint32
|
||||
BlocksCountHigh uint32
|
||||
RBlocksCountHigh uint32
|
||||
FreeBlocksCountHigh uint32
|
||||
MinExtraIsize uint16
|
||||
WantExtraIsize uint16
|
||||
Flags uint32
|
||||
RaidStride uint16
|
||||
MmpInterval uint16
|
||||
MmpBlock uint64
|
||||
RaidStripeWidth uint32
|
||||
LogGroupsPerFlex uint8
|
||||
ChecksumType uint8
|
||||
ReservedPad uint16
|
||||
KbytesWritten uint64
|
||||
SnapshotInum uint32
|
||||
SnapshotID uint32
|
||||
SnapshotRBlocksCount uint64
|
||||
SnapshotList uint32
|
||||
ErrorCount uint32
|
||||
FirstErrorTime uint32
|
||||
FirstErrorInode uint32
|
||||
FirstErrorBlock uint64
|
||||
FirstErrorFunc [32]uint8
|
||||
FirstErrorLine uint32
|
||||
LastErrorTime uint32
|
||||
LastErrorInode uint32
|
||||
LastErrorLine uint32
|
||||
LastErrorBlock uint64
|
||||
LastErrorFunc [32]uint8
|
||||
MountOpts [64]uint8
|
||||
UserQuotaInum uint32
|
||||
GroupQuotaInum uint32
|
||||
OverheadBlocks uint32
|
||||
BackupBgs [2]uint32
|
||||
EncryptAlgos [4]uint8
|
||||
EncryptPwSalt [16]uint8
|
||||
LpfInode uint32
|
||||
ProjectQuotaInum uint32
|
||||
ChecksumSeed uint32
|
||||
WtimeHigh uint8
|
||||
MtimeHigh uint8
|
||||
MkfsTimeHigh uint8
|
||||
LastcheckHigh uint8
|
||||
FirstErrorTimeHigh uint8
|
||||
LastErrorTimeHigh uint8
|
||||
Pad [2]uint8
|
||||
Reserved [96]uint32
|
||||
Checksum uint32
|
||||
}
|
||||
|
||||
const SuperBlockMagic uint16 = 0xef53
|
||||
|
||||
type CompatFeature uint32
|
||||
type IncompatFeature uint32
|
||||
type RoCompatFeature uint32
|
||||
|
||||
const (
|
||||
CompatDirPrealloc CompatFeature = 0x1
|
||||
CompatImagicInodes CompatFeature = 0x2
|
||||
CompatHasJournal CompatFeature = 0x4
|
||||
CompatExtAttr CompatFeature = 0x8
|
||||
CompatResizeInode CompatFeature = 0x10
|
||||
CompatDirIndex CompatFeature = 0x20
|
||||
CompatLazyBg CompatFeature = 0x40
|
||||
CompatExcludeInode CompatFeature = 0x80
|
||||
CompatExcludeBitmap CompatFeature = 0x100
|
||||
CompatSparseSuper2 CompatFeature = 0x200
|
||||
|
||||
IncompatCompression IncompatFeature = 0x1
|
||||
IncompatFiletype IncompatFeature = 0x2
|
||||
IncompatRecover IncompatFeature = 0x4
|
||||
IncompatJournalDev IncompatFeature = 0x8
|
||||
IncompatMetaBg IncompatFeature = 0x10
|
||||
IncompatExtents IncompatFeature = 0x40
|
||||
Incompat_64Bit IncompatFeature = 0x80
|
||||
IncompatMmp IncompatFeature = 0x100
|
||||
IncompatFlexBg IncompatFeature = 0x200
|
||||
IncompatEaInode IncompatFeature = 0x400
|
||||
IncompatDirdata IncompatFeature = 0x1000
|
||||
IncompatCsumSeed IncompatFeature = 0x2000
|
||||
IncompatLargedir IncompatFeature = 0x4000
|
||||
IncompatInlineData IncompatFeature = 0x8000
|
||||
IncompatEncrypt IncompatFeature = 0x10000
|
||||
|
||||
RoCompatSparseSuper RoCompatFeature = 0x1
|
||||
RoCompatLargeFile RoCompatFeature = 0x2
|
||||
RoCompatBtreeDir RoCompatFeature = 0x4
|
||||
RoCompatHugeFile RoCompatFeature = 0x8
|
||||
RoCompatGdtCsum RoCompatFeature = 0x10
|
||||
RoCompatDirNlink RoCompatFeature = 0x20
|
||||
RoCompatExtraIsize RoCompatFeature = 0x40
|
||||
RoCompatHasSnapshot RoCompatFeature = 0x80
|
||||
RoCompatQuota RoCompatFeature = 0x100
|
||||
RoCompatBigalloc RoCompatFeature = 0x200
|
||||
RoCompatMetadataCsum RoCompatFeature = 0x400
|
||||
RoCompatReplica RoCompatFeature = 0x800
|
||||
RoCompatReadonly RoCompatFeature = 0x1000
|
||||
RoCompatProject RoCompatFeature = 0x2000
|
||||
)
|
||||
|
||||
type BlockGroupFlag uint16
|
||||
|
||||
const (
|
||||
BlockGroupInodeUninit BlockGroupFlag = 0x1
|
||||
BlockGroupBlockUninit BlockGroupFlag = 0x2
|
||||
BlockGroupInodeZeroed BlockGroupFlag = 0x4
|
||||
)
|
||||
|
||||
type GroupDescriptor struct {
|
||||
BlockBitmapLow uint32
|
||||
InodeBitmapLow uint32
|
||||
InodeTableLow uint32
|
||||
FreeBlocksCountLow uint16
|
||||
FreeInodesCountLow uint16
|
||||
UsedDirsCountLow uint16
|
||||
Flags BlockGroupFlag
|
||||
ExcludeBitmapLow uint32
|
||||
BlockBitmapCsumLow uint16
|
||||
InodeBitmapCsumLow uint16
|
||||
ItableUnusedLow uint16
|
||||
Checksum uint16
|
||||
}
|
||||
|
||||
type GroupDescriptor64 struct {
|
||||
GroupDescriptor
|
||||
BlockBitmapHigh uint32
|
||||
InodeBitmapHigh uint32
|
||||
InodeTableHigh uint32
|
||||
FreeBlocksCountHigh uint16
|
||||
FreeInodesCountHigh uint16
|
||||
UsedDirsCountHigh uint16
|
||||
ItableUnusedHigh uint16
|
||||
ExcludeBitmapHigh uint32
|
||||
BlockBitmapCsumHigh uint16
|
||||
InodeBitmapCsumHigh uint16
|
||||
Reserved uint32
|
||||
}
|
||||
|
||||
const (
|
||||
S_IXOTH = 0x1
|
||||
S_IWOTH = 0x2
|
||||
S_IROTH = 0x4
|
||||
S_IXGRP = 0x8
|
||||
S_IWGRP = 0x10
|
||||
S_IRGRP = 0x20
|
||||
S_IXUSR = 0x40
|
||||
S_IWUSR = 0x80
|
||||
S_IRUSR = 0x100
|
||||
S_ISVTX = 0x200
|
||||
S_ISGID = 0x400
|
||||
S_ISUID = 0x800
|
||||
S_IFIFO = 0x1000
|
||||
S_IFCHR = 0x2000
|
||||
S_IFDIR = 0x4000
|
||||
S_IFBLK = 0x6000
|
||||
S_IFREG = 0x8000
|
||||
S_IFLNK = 0xA000
|
||||
S_IFSOCK = 0xC000
|
||||
|
||||
TypeMask uint16 = 0xF000
|
||||
)
|
||||
|
||||
type InodeNumber uint32
|
||||
|
||||
const (
|
||||
InodeRoot = 2
|
||||
)
|
||||
|
||||
type Inode struct {
|
||||
Mode uint16
|
||||
Uid uint16
|
||||
SizeLow uint32
|
||||
Atime uint32
|
||||
Ctime uint32
|
||||
Mtime uint32
|
||||
Dtime uint32
|
||||
Gid uint16
|
||||
LinksCount uint16
|
||||
BlocksLow uint32
|
||||
Flags InodeFlag
|
||||
Version uint32
|
||||
Block [60]byte
|
||||
Generation uint32
|
||||
XattrBlockLow uint32
|
||||
SizeHigh uint32
|
||||
ObsoleteFragmentAddr uint32
|
||||
BlocksHigh uint16
|
||||
XattrBlockHigh uint16
|
||||
UidHigh uint16
|
||||
GidHigh uint16
|
||||
ChecksumLow uint16
|
||||
Reserved uint16
|
||||
ExtraIsize uint16
|
||||
ChecksumHigh uint16
|
||||
CtimeExtra uint32
|
||||
MtimeExtra uint32
|
||||
AtimeExtra uint32
|
||||
Crtime uint32
|
||||
CrtimeExtra uint32
|
||||
VersionHigh uint32
|
||||
Projid uint32
|
||||
}
|
||||
|
||||
type InodeFlag uint32
|
||||
|
||||
const (
|
||||
InodeFlagSecRm InodeFlag = 0x1
|
||||
InodeFlagUnRm InodeFlag = 0x2
|
||||
InodeFlagCompressed InodeFlag = 0x4
|
||||
InodeFlagSync InodeFlag = 0x8
|
||||
InodeFlagImmutable InodeFlag = 0x10
|
||||
InodeFlagAppend InodeFlag = 0x20
|
||||
InodeFlagNoDump InodeFlag = 0x40
|
||||
InodeFlagNoAtime InodeFlag = 0x80
|
||||
InodeFlagDirtyCompressed InodeFlag = 0x100
|
||||
InodeFlagCompressedClusters InodeFlag = 0x200
|
||||
InodeFlagNoCompress InodeFlag = 0x400
|
||||
InodeFlagEncrypted InodeFlag = 0x800
|
||||
InodeFlagHashedIndex InodeFlag = 0x1000
|
||||
InodeFlagMagic InodeFlag = 0x2000
|
||||
InodeFlagJournalData InodeFlag = 0x4000
|
||||
InodeFlagNoTail InodeFlag = 0x8000
|
||||
InodeFlagDirSync InodeFlag = 0x10000
|
||||
InodeFlagTopDir InodeFlag = 0x20000
|
||||
InodeFlagHugeFile InodeFlag = 0x40000
|
||||
InodeFlagExtents InodeFlag = 0x80000
|
||||
InodeFlagEaInode InodeFlag = 0x200000
|
||||
InodeFlagEOFBlocks InodeFlag = 0x400000
|
||||
InodeFlagSnapfile InodeFlag = 0x01000000
|
||||
InodeFlagSnapfileDeleted InodeFlag = 0x04000000
|
||||
InodeFlagSnapfileShrunk InodeFlag = 0x08000000
|
||||
InodeFlagInlineData InodeFlag = 0x10000000
|
||||
InodeFlagProjectIDInherit InodeFlag = 0x20000000
|
||||
InodeFlagReserved InodeFlag = 0x80000000
|
||||
)
|
||||
|
||||
const (
|
||||
MaxLinks = 65000
|
||||
)
|
||||
|
||||
type ExtentHeader struct {
|
||||
Magic uint16
|
||||
Entries uint16
|
||||
Max uint16
|
||||
Depth uint16
|
||||
Generation uint32
|
||||
}
|
||||
|
||||
const ExtentHeaderMagic uint16 = 0xf30a
|
||||
|
||||
type ExtentIndexNode struct {
|
||||
Block uint32
|
||||
LeafLow uint32
|
||||
LeafHigh uint16
|
||||
Unused uint16
|
||||
}
|
||||
|
||||
type ExtentLeafNode struct {
|
||||
Block uint32
|
||||
Length uint16
|
||||
StartHigh uint16
|
||||
StartLow uint32
|
||||
}
|
||||
|
||||
type ExtentTail struct {
|
||||
Checksum uint32
|
||||
}
|
||||
|
||||
type DirectoryEntry struct {
|
||||
Inode InodeNumber
|
||||
RecordLength uint16
|
||||
NameLength uint8
|
||||
FileType FileType
|
||||
//Name []byte
|
||||
}
|
||||
|
||||
type FileType uint8
|
||||
|
||||
const (
|
||||
FileTypeUnknown FileType = 0x0
|
||||
FileTypeRegular FileType = 0x1
|
||||
FileTypeDirectory FileType = 0x2
|
||||
FileTypeCharacter FileType = 0x3
|
||||
FileTypeBlock FileType = 0x4
|
||||
FileTypeFIFO FileType = 0x5
|
||||
FileTypeSocket FileType = 0x6
|
||||
FileTypeSymbolicLink FileType = 0x7
|
||||
)
|
||||
|
||||
type DirectoryEntryTail struct {
|
||||
ReservedZero1 uint32
|
||||
RecordLength uint16
|
||||
ReservedZero2 uint8
|
||||
FileType uint8
|
||||
Checksum uint32
|
||||
}
|
||||
|
||||
type DirectoryTreeRoot struct {
|
||||
Dot DirectoryEntry
|
||||
DotName [4]byte
|
||||
DotDot DirectoryEntry
|
||||
DotDotName [4]byte
|
||||
ReservedZero uint32
|
||||
HashVersion uint8
|
||||
InfoLength uint8
|
||||
IndirectLevels uint8
|
||||
UnusedFlags uint8
|
||||
Limit uint16
|
||||
Count uint16
|
||||
Block uint32
|
||||
//Entries []DirectoryTreeEntry
|
||||
}
|
||||
|
||||
type DirectoryTreeNode struct {
|
||||
FakeInode uint32
|
||||
FakeRecordLength uint16
|
||||
NameLength uint8
|
||||
FileType uint8
|
||||
Limit uint16
|
||||
Count uint16
|
||||
Block uint32
|
||||
//Entries []DirectoryTreeEntry
|
||||
}
|
||||
|
||||
type DirectoryTreeEntry struct {
|
||||
Hash uint32
|
||||
Block uint32
|
||||
}
|
||||
|
||||
type DirectoryTreeTail struct {
|
||||
Reserved uint32
|
||||
Checksum uint32
|
||||
}
|
||||
|
||||
type XAttrInodeBodyHeader struct {
|
||||
Magic uint32
|
||||
}
|
||||
|
||||
type XAttrHeader struct {
|
||||
Magic uint32
|
||||
ReferenceCount uint32
|
||||
Blocks uint32
|
||||
Hash uint32
|
||||
Checksum uint32
|
||||
Reserved [3]uint32
|
||||
}
|
||||
|
||||
const XAttrHeaderMagic uint32 = 0xea020000
|
||||
|
||||
type XAttrEntry struct {
|
||||
NameLength uint8
|
||||
NameIndex uint8
|
||||
ValueOffset uint16
|
||||
ValueInum uint32
|
||||
ValueSize uint32
|
||||
Hash uint32
|
||||
//Name []byte
|
||||
}
|
174
vendor/github.com/Microsoft/hcsshim/ext4/tar2ext4/tar2ext4.go
generated
vendored
Normal file
174
vendor/github.com/Microsoft/hcsshim/ext4/tar2ext4/tar2ext4.go
generated
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
package tar2ext4
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/Microsoft/hcsshim/ext4/internal/compactext4"
|
||||
)
|
||||
|
||||
type params struct {
|
||||
convertWhiteout bool
|
||||
appendVhdFooter bool
|
||||
ext4opts []compactext4.Option
|
||||
}
|
||||
|
||||
// Option is the type for optional parameters to Convert.
|
||||
type Option func(*params)
|
||||
|
||||
// ConvertWhiteout instructs the converter to convert OCI-style whiteouts
|
||||
// (beginning with .wh.) to overlay-style whiteouts.
|
||||
func ConvertWhiteout(p *params) {
|
||||
p.convertWhiteout = true
|
||||
}
|
||||
|
||||
// AppendVhdFooter instructs the converter to add a fixed VHD footer to the
|
||||
// file.
|
||||
func AppendVhdFooter(p *params) {
|
||||
p.appendVhdFooter = true
|
||||
}
|
||||
|
||||
// InlineData instructs the converter to write small files into the inode
|
||||
// structures directly. This creates smaller images but currently is not
|
||||
// compatible with DAX.
|
||||
func InlineData(p *params) {
|
||||
p.ext4opts = append(p.ext4opts, compactext4.InlineData)
|
||||
}
|
||||
|
||||
// MaximumDiskSize instructs the writer to limit the disk size to the specified
|
||||
// value. This also reserves enough metadata space for the specified disk size.
|
||||
// If not provided, then 16GB is the default.
|
||||
func MaximumDiskSize(size int64) Option {
|
||||
return func(p *params) {
|
||||
p.ext4opts = append(p.ext4opts, compactext4.MaximumDiskSize(size))
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
whiteoutPrefix = ".wh."
|
||||
opaqueWhiteout = ".wh..wh..opq"
|
||||
)
|
||||
|
||||
// Convert writes a compact ext4 file system image that contains the files in the
|
||||
// input tar stream.
|
||||
func Convert(r io.Reader, w io.ReadWriteSeeker, options ...Option) error {
|
||||
var p params
|
||||
for _, opt := range options {
|
||||
opt(&p)
|
||||
}
|
||||
t := tar.NewReader(bufio.NewReader(r))
|
||||
fs := compactext4.NewWriter(w, p.ext4opts...)
|
||||
for {
|
||||
hdr, err := t.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.convertWhiteout {
|
||||
dir, name := path.Split(hdr.Name)
|
||||
if strings.HasPrefix(name, whiteoutPrefix) {
|
||||
if name == opaqueWhiteout {
|
||||
// Update the directory with the appropriate xattr.
|
||||
f, err := fs.Stat(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Xattrs["trusted.overlay.opaque"] = []byte("y")
|
||||
err = fs.Create(dir, f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Create an overlay-style whiteout.
|
||||
f := &compactext4.File{
|
||||
Mode: compactext4.S_IFCHR,
|
||||
Devmajor: 0,
|
||||
Devminor: 0,
|
||||
}
|
||||
err = fs.Create(path.Join(dir, name[len(whiteoutPrefix):]), f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if hdr.Typeflag == tar.TypeLink {
|
||||
err = fs.Link(hdr.Linkname, hdr.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
f := &compactext4.File{
|
||||
Mode: uint16(hdr.Mode),
|
||||
Atime: hdr.AccessTime,
|
||||
Mtime: hdr.ModTime,
|
||||
Ctime: hdr.ChangeTime,
|
||||
Crtime: hdr.ModTime,
|
||||
Size: hdr.Size,
|
||||
Uid: uint32(hdr.Uid),
|
||||
Gid: uint32(hdr.Gid),
|
||||
Linkname: hdr.Linkname,
|
||||
Devmajor: uint32(hdr.Devmajor),
|
||||
Devminor: uint32(hdr.Devminor),
|
||||
Xattrs: make(map[string][]byte),
|
||||
}
|
||||
for key, value := range hdr.PAXRecords {
|
||||
const xattrPrefix = "SCHILY.xattr."
|
||||
if strings.HasPrefix(key, xattrPrefix) {
|
||||
f.Xattrs[key[len(xattrPrefix):]] = []byte(value)
|
||||
}
|
||||
}
|
||||
|
||||
var typ uint16
|
||||
switch hdr.Typeflag {
|
||||
case tar.TypeReg, tar.TypeRegA:
|
||||
typ = compactext4.S_IFREG
|
||||
case tar.TypeSymlink:
|
||||
typ = compactext4.S_IFLNK
|
||||
case tar.TypeChar:
|
||||
typ = compactext4.S_IFCHR
|
||||
case tar.TypeBlock:
|
||||
typ = compactext4.S_IFBLK
|
||||
case tar.TypeDir:
|
||||
typ = compactext4.S_IFDIR
|
||||
case tar.TypeFifo:
|
||||
typ = compactext4.S_IFIFO
|
||||
}
|
||||
f.Mode &= ^compactext4.TypeMask
|
||||
f.Mode |= typ
|
||||
err = fs.Create(hdr.Name, f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(fs, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
err := fs.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if p.appendVhdFooter {
|
||||
size, err := w.Seek(0, io.SeekEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, makeFixedVHDFooter(size))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
76
vendor/github.com/Microsoft/hcsshim/ext4/tar2ext4/vhdfooter.go
generated
vendored
Normal file
76
vendor/github.com/Microsoft/hcsshim/ext4/tar2ext4/vhdfooter.go
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
package tar2ext4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// Constants for the VHD footer
|
||||
const (
|
||||
cookieMagic = "conectix"
|
||||
featureMask = 0x2
|
||||
fileFormatVersionMagic = 0x00010000
|
||||
fixedDataOffset = -1
|
||||
creatorVersionMagic = 0x000a0000
|
||||
diskTypeFixed = 2
|
||||
)
|
||||
|
||||
type vhdFooter struct {
|
||||
Cookie [8]byte
|
||||
Features uint32
|
||||
FileFormatVersion uint32
|
||||
DataOffset int64
|
||||
TimeStamp uint32
|
||||
CreatorApplication [4]byte
|
||||
CreatorVersion uint32
|
||||
CreatorHostOS [4]byte
|
||||
OriginalSize int64
|
||||
CurrentSize int64
|
||||
DiskGeometry uint32
|
||||
DiskType uint32
|
||||
Checksum uint32
|
||||
UniqueID [16]uint8
|
||||
SavedState uint8
|
||||
Reserved [427]uint8
|
||||
}
|
||||
|
||||
func makeFixedVHDFooter(size int64) *vhdFooter {
|
||||
footer := &vhdFooter{
|
||||
Features: featureMask,
|
||||
FileFormatVersion: fileFormatVersionMagic,
|
||||
DataOffset: fixedDataOffset,
|
||||
CreatorVersion: creatorVersionMagic,
|
||||
OriginalSize: size,
|
||||
CurrentSize: size,
|
||||
DiskType: diskTypeFixed,
|
||||
UniqueID: generateUUID(),
|
||||
}
|
||||
copy(footer.Cookie[:], cookieMagic)
|
||||
footer.Checksum = calculateCheckSum(footer)
|
||||
return footer
|
||||
}
|
||||
|
||||
func calculateCheckSum(footer *vhdFooter) uint32 {
|
||||
oldchk := footer.Checksum
|
||||
footer.Checksum = 0
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
binary.Write(buf, binary.BigEndian, footer)
|
||||
|
||||
var chk uint32
|
||||
bufBytes := buf.Bytes()
|
||||
for i := 0; i < len(bufBytes); i++ {
|
||||
chk += uint32(bufBytes[i])
|
||||
}
|
||||
footer.Checksum = oldchk
|
||||
return uint32(^chk)
|
||||
}
|
||||
|
||||
func generateUUID() [16]byte {
|
||||
res := [16]byte{}
|
||||
if _, err := rand.Read(res[:]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return res
|
||||
}
|
Reference in New Issue
Block a user