github.com/mgoltzsche/ctnr@v0.7.1-alpha/pkg/fs/writer/tarwriter_test.go (about) 1 package writer 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "syscall" 10 "testing" 11 "time" 12 13 "github.com/mgoltzsche/ctnr/pkg/fs" 14 "github.com/mgoltzsche/ctnr/pkg/fs/source" 15 "github.com/mgoltzsche/ctnr/pkg/fs/testutils" 16 "github.com/mgoltzsche/ctnr/pkg/idutils" 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func TestTarWriter(t *testing.T) { 22 tmpDir, err := ioutil.TempDir("", "test-tar-writer-") 23 require.NoError(t, err) 24 defer os.RemoveAll(tmpDir) 25 extDir := filepath.Join(tmpDir, "extracted") 26 err = os.Mkdir(extDir, 0755) 27 require.NoError(t, err) 28 tarFile := filepath.Join(tmpDir, "archive.tar") 29 f, err := os.OpenFile(tarFile, os.O_CREATE|os.O_RDWR, 0644) 30 require.NoError(t, err) 31 defer f.Close() 32 33 testee := NewTarWriter(f) 34 defer testee.Close() 35 36 // Test write operations 37 times := fs.FileTimes{} 38 times.Mtime, err = time.Parse(time.RFC3339, "2018-02-23T01:01:42Z") 39 require.NoError(t, err) 40 times.Mtime = time.Unix(times.Mtime.Unix(), 123) 41 times.Atime, err = time.Parse(time.RFC3339, "2018-01-23T01:01:43Z") 42 require.NoError(t, err) 43 usr := idutils.UserIds{uint(os.Getuid()), uint(os.Getgid())} 44 dirAttrs := fs.FileAttrs{Mode: os.ModeDir | 0755, UserIds: usr, FileTimes: times} 45 dirAttrs2 := dirAttrs 46 dirAttrs2.Mode = os.ModeDir | 0775 47 fileAttrsA := fs.NodeAttrs{NodeInfo: fs.NodeInfo{fs.TypeFile, fs.FileAttrs{Mode: 0640, UserIds: usr, Size: 1, FileTimes: times}}} 48 fileAttrsB := fs.NodeAttrs{NodeInfo: fs.NodeInfo{fs.TypeFile, fs.FileAttrs{Mode: 0755, UserIds: usr, Size: 3, FileTimes: times}}} 49 linkAttrs := fs.FileAttrs{Mode: os.ModeSymlink, UserIds: usr, FileTimes: times} 50 fifoAttrs := fs.DeviceAttrs{fs.FileAttrs{Mode: syscall.S_IFIFO | 0640, UserIds: usr, FileTimes: times}, 1, 1} 51 fileA := source.NewSourceFile(fs.NewReadableBytes([]byte("a")), fileAttrsA.FileAttrs) 52 fileB := source.NewSourceFile(fs.NewReadableBytes([]byte("bbb")), fileAttrsB.FileAttrs) 53 err = testee.Dir("/", "", dirAttrs2) 54 require.NoError(t, err) 55 err = testee.Dir("etc", "", dirAttrs2) 56 require.NoError(t, err) 57 reader, err := testee.File("etc/fileA", fileA) 58 require.NoError(t, err) 59 assert.Equal(t, fileA, reader, "returned FileSource of File()") 60 _, err = testee.File("/etc/fileB", fileB) 61 require.NoError(t, err) 62 err = testee.Fifo("/etc/fifo", fifoAttrs) 63 require.NoError(t, err) 64 err = testee.Device("/etc/devA", fifoAttrs) 65 require.NoError(t, err) 66 err = testee.Link("/etc/link-abs", "/etc/fileA") 67 require.NoError(t, err) 68 err = testee.Link("/etc/link-rel", "../etc/fileA") 69 require.NoError(t, err) 70 err = testee.Dir("/dir", "", dirAttrs) 71 require.NoError(t, err) 72 _, err = testee.File("/dir/file1", fileA) 73 require.NoError(t, err) 74 _, err = testee.File("/dir/file2", fileB) 75 require.NoError(t, err) 76 err = testee.Dir("/dir/ndir", "", fs.FileAttrs{Mode: os.ModeDir | 0754, UserIds: usr}) 77 require.NoError(t, err) 78 _, err = testee.File("/dir/ndir/nestedfile", fileA) 79 require.NoError(t, err) 80 linkAttrs.Symlink = "../etc/fileA" 81 err = testee.Symlink("etc/symlink-rel", linkAttrs) 82 require.NoError(t, err) 83 linkAttrs.Symlink = "/etc/fileB" 84 err = testee.Symlink("etc/symlink-abs", linkAttrs) 85 require.NoError(t, err) 86 87 // Test paths sanitized 88 linkAttrs.Symlink = filepath.Join("..", "..") 89 err = testee.Symlink("etc/symlink-sanitized", linkAttrs) 90 require.NoError(t, err) 91 _, err = testee.File("/../filepathsanitized", fileA) 92 require.NoError(t, err) 93 94 err = testee.Close() 95 require.NoError(t, err) 96 97 // Untar archive and compare file system without timestamps using tar 98 cmd := exec.Command("tar", "-xf", tarFile) 99 cmd.Dir = extDir 100 var buf bytes.Buffer 101 cmd.Stdout = &buf 102 cmd.Stderr = &buf 103 err = cmd.Run() 104 require.NoError(t, err, buf.String()) 105 // Cannot test time metadata here since tar -xf does not preserve it 106 // for every file type 107 testutils.AssertFsState(t, extDir, "", testutils.MtreeTestkeywords, ` 108 # . 109 . size=4096 type=dir mode=0775 110 filepathsanitized mode=0640 111 # dir 112 dir type=dir mode=0755 113 file1 mode=0640 114 file2 mode=0755 115 116 # dir/ndir 117 ndir type=dir mode=0754 118 nestedfile type=file mode=0640 119 .. 120 .. 121 # bin 122 etc type=dir mode=0775 123 devA mode=0640 124 fifo mode=0640 125 fileA mode=0640 126 fileB mode=0755 127 link-abs mode=0640 nlink=3 128 link-rel mode=0640 nlink=3 129 symlink-abs type=link mode=0777 link=$ROOT/etc/fileB 130 symlink-rel type=link mode=0777 link=../etc/fileA 131 symlink-sanitized type=link mode=0777 link=.. 132 .. 133 `) 134 // Test mtime applied to file 135 // (Compare only unix seconds since tar does not provide nanoseconds) 136 file1 := filepath.Join(extDir, "dir/file1") 137 st, err := os.Stat(file1) 138 require.NoError(t, err) 139 assert.Equal(t, times.Mtime.Unix(), st.ModTime().Unix(), "mtime should be applied") 140 }