1package dump
2
3import (
4	"archive/tar"
5	"bytes"
6	"fmt"
7	"io"
8	"io/ioutil"
9	"os"
10	"path/filepath"
11	"strings"
12	"testing"
13	"time"
14
15	"github.com/restic/restic/internal/fs"
16)
17
18func TestWriteTar(t *testing.T) {
19	WriteTest(t, WriteTar, checkTar)
20}
21
22func checkTar(t *testing.T, testDir string, srcTar *bytes.Buffer) error {
23	tr := tar.NewReader(srcTar)
24
25	fileNumber := 0
26	tarFiles := 0
27
28	err := filepath.Walk(testDir, func(path string, info os.FileInfo, err error) error {
29		if err != nil {
30			return err
31		}
32		if info.Name() != filepath.Base(testDir) {
33			fileNumber++
34		}
35		return nil
36	})
37	if err != nil {
38		return err
39	}
40
41	for {
42		hdr, err := tr.Next()
43		if err == io.EOF {
44			break
45		}
46		if err != nil {
47			t.Fatal(err)
48		}
49
50		matchPath := filepath.Join(testDir, hdr.Name)
51		match, err := os.Lstat(matchPath)
52		if err != nil {
53			return err
54		}
55
56		// check metadata, tar header contains time rounded to seconds
57		fileTime := match.ModTime().Round(time.Second)
58		tarTime := hdr.ModTime
59		if !fileTime.Equal(tarTime) {
60			return fmt.Errorf("modTime does not match, got: %s, want: %s", fileTime, tarTime)
61		}
62
63		if os.FileMode(hdr.Mode).Perm() != match.Mode().Perm() || os.FileMode(hdr.Mode)&^os.ModePerm != 0 {
64			return fmt.Errorf("mode does not match, got: %v, want: %v", os.FileMode(hdr.Mode), match.Mode())
65		}
66
67		switch hdr.Typeflag {
68		case tar.TypeDir:
69			// this is a folder
70			if hdr.Name == "." {
71				// we don't need to check the root folder
72				continue
73			}
74
75			filebase := filepath.ToSlash(match.Name())
76			if filepath.Base(hdr.Name) != filebase {
77				return fmt.Errorf("foldernames don't match got %v want %v", filepath.Base(hdr.Name), filebase)
78			}
79			if !strings.HasSuffix(hdr.Name, "/") {
80				return fmt.Errorf("foldernames must end with separator got %v", hdr.Name)
81			}
82		case tar.TypeSymlink:
83			target, err := fs.Readlink(matchPath)
84			if err != nil {
85				return err
86			}
87			if target != hdr.Linkname {
88				return fmt.Errorf("symlink target does not match, got %s want %s", target, hdr.Linkname)
89			}
90		default:
91			if match.Size() != hdr.Size {
92				return fmt.Errorf("size does not match got %v want %v", hdr.Size, match.Size())
93			}
94			contentsFile, err := ioutil.ReadFile(matchPath)
95			if err != nil {
96				t.Fatal(err)
97			}
98			contentsTar := &bytes.Buffer{}
99			_, err = io.Copy(contentsTar, tr)
100			if err != nil {
101				t.Fatal(err)
102			}
103			if contentsTar.String() != string(contentsFile) {
104				return fmt.Errorf("contents does not match, got %s want %s", contentsTar, contentsFile)
105			}
106		}
107		tarFiles++
108	}
109
110	if tarFiles != fileNumber {
111		return fmt.Errorf("not the same amount of files got %v want %v", tarFiles, fileNumber)
112	}
113
114	return nil
115}
116