github.com/Serizao/go-winio@v0.0.0-20230906082528-f02f7f4ad6e8/backup_test.go (about)

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