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) } }