1package winio
2
3import (
4	"io"
5	"io/ioutil"
6	"os"
7	"syscall"
8	"testing"
9)
10
11var testFileName string
12
13func TestMain(m *testing.M) {
14	f, err := ioutil.TempFile("", "tmp")
15	if err != nil {
16		panic(err)
17	}
18	testFileName = f.Name()
19	f.Close()
20	defer os.Remove(testFileName)
21	os.Exit(m.Run())
22}
23
24func makeTestFile(makeADS bool) error {
25	os.Remove(testFileName)
26	f, err := os.Create(testFileName)
27	if err != nil {
28		return err
29	}
30	defer f.Close()
31	_, err = f.Write([]byte("testing 1 2 3\n"))
32	if err != nil {
33		return err
34	}
35	if makeADS {
36		a, err := os.Create(testFileName + ":ads.txt")
37		if err != nil {
38			return err
39		}
40		defer a.Close()
41		_, err = a.Write([]byte("alternate data stream\n"))
42		if err != nil {
43			return err
44		}
45	}
46	return nil
47}
48
49func TestBackupRead(t *testing.T) {
50	err := makeTestFile(true)
51	if err != nil {
52		t.Fatal(err)
53	}
54
55	f, err := os.Open(testFileName)
56	if err != nil {
57		t.Fatal(err)
58	}
59	defer f.Close()
60	r := NewBackupFileReader(f, false)
61	defer r.Close()
62	b, err := ioutil.ReadAll(r)
63	if err != nil {
64		t.Fatal(err)
65	}
66	if len(b) == 0 {
67		t.Fatal("no data")
68	}
69}
70
71func TestBackupStreamRead(t *testing.T) {
72	err := makeTestFile(true)
73	if err != nil {
74		t.Fatal(err)
75	}
76
77	f, err := os.Open(testFileName)
78	if err != nil {
79		t.Fatal(err)
80	}
81	defer f.Close()
82	r := NewBackupFileReader(f, false)
83	defer r.Close()
84
85	br := NewBackupStreamReader(r)
86	gotData := false
87	gotAltData := false
88	for {
89		hdr, err := br.Next()
90		if err == io.EOF {
91			break
92		}
93		if err != nil {
94			t.Fatal(err)
95		}
96
97		switch hdr.Id {
98		case BackupData:
99			if gotData {
100				t.Fatal("duplicate data")
101			}
102			if hdr.Name != "" {
103				t.Fatalf("unexpected name %s", hdr.Name)
104			}
105			b, err := ioutil.ReadAll(br)
106			if err != nil {
107				t.Fatal(err)
108			}
109			if string(b) != "testing 1 2 3\n" {
110				t.Fatalf("incorrect data %v", b)
111			}
112			gotData = true
113		case BackupAlternateData:
114			if gotAltData {
115				t.Fatal("duplicate alt data")
116			}
117			if hdr.Name != ":ads.txt:$DATA" {
118				t.Fatalf("incorrect name %s", hdr.Name)
119			}
120			b, err := ioutil.ReadAll(br)
121			if err != nil {
122				t.Fatal(err)
123			}
124			if string(b) != "alternate data stream\n" {
125				t.Fatalf("incorrect data %v", b)
126			}
127			gotAltData = true
128		default:
129			t.Fatalf("unknown stream ID %d", hdr.Id)
130		}
131	}
132	if !gotData || !gotAltData {
133		t.Fatal("missing stream")
134	}
135}
136
137func TestBackupStreamWrite(t *testing.T) {
138	f, err := os.Create(testFileName)
139	if err != nil {
140		t.Fatal(err)
141	}
142	defer f.Close()
143	w := NewBackupFileWriter(f, false)
144	defer w.Close()
145
146	data := "testing 1 2 3\n"
147	altData := "alternate stream\n"
148
149	br := NewBackupStreamWriter(w)
150	err = br.WriteHeader(&BackupHeader{Id: BackupData, Size: int64(len(data))})
151	if err != nil {
152		t.Fatal(err)
153	}
154	n, err := br.Write([]byte(data))
155	if err != nil {
156		t.Fatal(err)
157	}
158	if n != len(data) {
159		t.Fatal("short write")
160	}
161
162	err = br.WriteHeader(&BackupHeader{Id: BackupAlternateData, Size: int64(len(altData)), Name: ":ads.txt:$DATA"})
163	if err != nil {
164		t.Fatal(err)
165	}
166	n, err = br.Write([]byte(altData))
167	if err != nil {
168		t.Fatal(err)
169	}
170	if n != len(altData) {
171		t.Fatal("short write")
172	}
173
174	f.Close()
175
176	b, err := ioutil.ReadFile(testFileName)
177	if err != nil {
178		t.Fatal(err)
179	}
180	if string(b) != data {
181		t.Fatalf("wrong data %v", b)
182	}
183
184	b, err = ioutil.ReadFile(testFileName + ":ads.txt")
185	if err != nil {
186		t.Fatal(err)
187	}
188	if string(b) != altData {
189		t.Fatalf("wrong data %v", b)
190	}
191}
192
193func makeSparseFile() error {
194	os.Remove(testFileName)
195	f, err := os.Create(testFileName)
196	if err != nil {
197		return err
198	}
199	defer f.Close()
200
201	const (
202		FSCTL_SET_SPARSE    = 0x000900c4
203		FSCTL_SET_ZERO_DATA = 0x000980c8
204	)
205
206	err = syscall.DeviceIoControl(syscall.Handle(f.Fd()), FSCTL_SET_SPARSE, nil, 0, nil, 0, nil, nil)
207	if err != nil {
208		return err
209	}
210
211	_, err = f.Write([]byte("testing 1 2 3\n"))
212	if err != nil {
213		return err
214	}
215
216	_, err = f.Seek(1000000, 0)
217	if err != nil {
218		return err
219	}
220
221	_, err = f.Write([]byte("more data later\n"))
222	if err != nil {
223		return err
224	}
225
226	return nil
227}
228
229func TestBackupSparseFile(t *testing.T) {
230	err := makeSparseFile()
231	if err != nil {
232		t.Fatal(err)
233	}
234
235	f, err := os.Open(testFileName)
236	if err != nil {
237		t.Fatal(err)
238	}
239	defer f.Close()
240	r := NewBackupFileReader(f, false)
241	defer r.Close()
242
243	br := NewBackupStreamReader(r)
244	for {
245		hdr, err := br.Next()
246		if err == io.EOF {
247			break
248		}
249		if err != nil {
250			t.Fatal(err)
251		}
252
253		t.Log(hdr)
254	}
255}
256