mirror of
https://github.com/rwinkhart/go-winio.git
synced 2026-08-28 12:56:33 -04:00
1.13 is sufficiently old at this point and net.ErrClosed from 1.16 will be nice to use. This change additionally runs go fmt to bring in the new 1.17 build tag syntax and builds the binaries in our CI with 1.17+. Signed-off-by: Daniel Canter <dcanter@microsoft.com>
259 lines
4.3 KiB
Go
259 lines
4.3 KiB
Go
//go:build windows
|
|
// +build windows
|
|
|
|
package winio
|
|
|
|
import (
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"syscall"
|
|
"testing"
|
|
)
|
|
|
|
var testFileName string
|
|
|
|
func TestMain(m *testing.M) {
|
|
f, err := ioutil.TempFile("", "tmp")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
testFileName = f.Name()
|
|
f.Close()
|
|
defer os.Remove(testFileName)
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func makeTestFile(makeADS bool) error {
|
|
os.Remove(testFileName)
|
|
f, err := os.Create(testFileName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
_, err = f.Write([]byte("testing 1 2 3\n"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if makeADS {
|
|
a, err := os.Create(testFileName + ":ads.txt")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer a.Close()
|
|
_, err = a.Write([]byte("alternate data stream\n"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func TestBackupRead(t *testing.T) {
|
|
err := makeTestFile(true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
f, err := os.Open(testFileName)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
r := NewBackupFileReader(f, false)
|
|
defer r.Close()
|
|
b, err := ioutil.ReadAll(r)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(b) == 0 {
|
|
t.Fatal("no data")
|
|
}
|
|
}
|
|
|
|
func TestBackupStreamRead(t *testing.T) {
|
|
err := makeTestFile(true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
f, err := os.Open(testFileName)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
r := NewBackupFileReader(f, false)
|
|
defer r.Close()
|
|
|
|
br := NewBackupStreamReader(r)
|
|
gotData := false
|
|
gotAltData := false
|
|
for {
|
|
hdr, err := br.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
switch hdr.Id {
|
|
case BackupData:
|
|
if gotData {
|
|
t.Fatal("duplicate data")
|
|
}
|
|
if hdr.Name != "" {
|
|
t.Fatalf("unexpected name %s", hdr.Name)
|
|
}
|
|
b, err := ioutil.ReadAll(br)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(b) != "testing 1 2 3\n" {
|
|
t.Fatalf("incorrect data %v", b)
|
|
}
|
|
gotData = true
|
|
case BackupAlternateData:
|
|
if gotAltData {
|
|
t.Fatal("duplicate alt data")
|
|
}
|
|
if hdr.Name != ":ads.txt:$DATA" {
|
|
t.Fatalf("incorrect name %s", hdr.Name)
|
|
}
|
|
b, err := ioutil.ReadAll(br)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(b) != "alternate data stream\n" {
|
|
t.Fatalf("incorrect data %v", b)
|
|
}
|
|
gotAltData = true
|
|
default:
|
|
t.Fatalf("unknown stream ID %d", hdr.Id)
|
|
}
|
|
}
|
|
if !gotData || !gotAltData {
|
|
t.Fatal("missing stream")
|
|
}
|
|
}
|
|
|
|
func TestBackupStreamWrite(t *testing.T) {
|
|
f, err := os.Create(testFileName)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
w := NewBackupFileWriter(f, false)
|
|
defer w.Close()
|
|
|
|
data := "testing 1 2 3\n"
|
|
altData := "alternate stream\n"
|
|
|
|
br := NewBackupStreamWriter(w)
|
|
err = br.WriteHeader(&BackupHeader{Id: BackupData, Size: int64(len(data))})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
n, err := br.Write([]byte(data))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != len(data) {
|
|
t.Fatal("short write")
|
|
}
|
|
|
|
err = br.WriteHeader(&BackupHeader{Id: BackupAlternateData, Size: int64(len(altData)), Name: ":ads.txt:$DATA"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
n, err = br.Write([]byte(altData))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != len(altData) {
|
|
t.Fatal("short write")
|
|
}
|
|
|
|
f.Close()
|
|
|
|
b, err := ioutil.ReadFile(testFileName)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(b) != data {
|
|
t.Fatalf("wrong data %v", b)
|
|
}
|
|
|
|
b, err = ioutil.ReadFile(testFileName + ":ads.txt")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(b) != altData {
|
|
t.Fatalf("wrong data %v", b)
|
|
}
|
|
}
|
|
|
|
func makeSparseFile() error {
|
|
os.Remove(testFileName)
|
|
f, err := os.Create(testFileName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
const (
|
|
FSCTL_SET_SPARSE = 0x000900c4
|
|
FSCTL_SET_ZERO_DATA = 0x000980c8
|
|
)
|
|
|
|
err = syscall.DeviceIoControl(syscall.Handle(f.Fd()), FSCTL_SET_SPARSE, nil, 0, nil, 0, nil, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = f.Write([]byte("testing 1 2 3\n"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = f.Seek(1000000, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = f.Write([]byte("more data later\n"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func TestBackupSparseFile(t *testing.T) {
|
|
err := makeSparseFile()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
f, err := os.Open(testFileName)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
r := NewBackupFileReader(f, false)
|
|
defer r.Close()
|
|
|
|
br := NewBackupStreamReader(r)
|
|
for {
|
|
hdr, err := br.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
t.Log(hdr)
|
|
}
|
|
}
|