github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/archive/tar/tar_test.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package tar 6 7 import ( 8 "bytes" 9 "io/ioutil" 10 "os" 11 "path" 12 "reflect" 13 "strings" 14 "testing" 15 "time" 16 ) 17 18 func TestFileInfoHeader(t *testing.T) { 19 fi, err := os.Stat("testdata/small.txt") 20 if err != nil { 21 t.Fatal(err) 22 } 23 h, err := FileInfoHeader(fi, "") 24 if err != nil { 25 t.Fatalf("FileInfoHeader: %v", err) 26 } 27 if g, e := h.Name, "small.txt"; g != e { 28 t.Errorf("Name = %q; want %q", g, e) 29 } 30 if g, e := h.Mode, int64(fi.Mode().Perm())|c_ISREG; g != e { 31 t.Errorf("Mode = %#o; want %#o", g, e) 32 } 33 if g, e := h.Size, int64(5); g != e { 34 t.Errorf("Size = %v; want %v", g, e) 35 } 36 if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) { 37 t.Errorf("ModTime = %v; want %v", g, e) 38 } 39 // FileInfoHeader should error when passing nil FileInfo 40 if _, err := FileInfoHeader(nil, ""); err == nil { 41 t.Fatalf("Expected error when passing nil to FileInfoHeader") 42 } 43 } 44 45 func TestFileInfoHeaderDir(t *testing.T) { 46 fi, err := os.Stat("testdata") 47 if err != nil { 48 t.Fatal(err) 49 } 50 h, err := FileInfoHeader(fi, "") 51 if err != nil { 52 t.Fatalf("FileInfoHeader: %v", err) 53 } 54 if g, e := h.Name, "testdata/"; g != e { 55 t.Errorf("Name = %q; want %q", g, e) 56 } 57 // Ignoring c_ISGID for golang.org/issue/4867 58 if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm())|c_ISDIR; g != e { 59 t.Errorf("Mode = %#o; want %#o", g, e) 60 } 61 if g, e := h.Size, int64(0); g != e { 62 t.Errorf("Size = %v; want %v", g, e) 63 } 64 if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) { 65 t.Errorf("ModTime = %v; want %v", g, e) 66 } 67 } 68 69 func TestFileInfoHeaderSymlink(t *testing.T) { 70 h, err := FileInfoHeader(symlink{}, "some-target") 71 if err != nil { 72 t.Fatal(err) 73 } 74 if g, e := h.Name, "some-symlink"; g != e { 75 t.Errorf("Name = %q; want %q", g, e) 76 } 77 if g, e := h.Linkname, "some-target"; g != e { 78 t.Errorf("Linkname = %q; want %q", g, e) 79 } 80 } 81 82 type symlink struct{} 83 84 func (symlink) Name() string { return "some-symlink" } 85 func (symlink) Size() int64 { return 0 } 86 func (symlink) Mode() os.FileMode { return os.ModeSymlink } 87 func (symlink) ModTime() time.Time { return time.Time{} } 88 func (symlink) IsDir() bool { return false } 89 func (symlink) Sys() interface{} { return nil } 90 91 func TestRoundTrip(t *testing.T) { 92 data := []byte("some file contents") 93 94 var b bytes.Buffer 95 tw := NewWriter(&b) 96 hdr := &Header{ 97 Name: "file.txt", 98 Uid: 1 << 21, // too big for 8 octal digits 99 Size: int64(len(data)), 100 // AddDate to strip monotonic clock reading, 101 // and Round to discard sub-second precision, 102 // both of which are not included in the tar header 103 // and would otherwise break the round-trip check 104 // below. 105 ModTime: time.Now().AddDate(0, 0, 0).Round(1 * time.Second), 106 } 107 if err := tw.WriteHeader(hdr); err != nil { 108 t.Fatalf("tw.WriteHeader: %v", err) 109 } 110 if _, err := tw.Write(data); err != nil { 111 t.Fatalf("tw.Write: %v", err) 112 } 113 if err := tw.Close(); err != nil { 114 t.Fatalf("tw.Close: %v", err) 115 } 116 117 // Read it back. 118 tr := NewReader(&b) 119 rHdr, err := tr.Next() 120 if err != nil { 121 t.Fatalf("tr.Next: %v", err) 122 } 123 if !reflect.DeepEqual(rHdr, hdr) { 124 t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr) 125 } 126 rData, err := ioutil.ReadAll(tr) 127 if err != nil { 128 t.Fatalf("Read: %v", err) 129 } 130 if !bytes.Equal(rData, data) { 131 t.Errorf("Data mismatch.\n got %q\nwant %q", rData, data) 132 } 133 } 134 135 type headerRoundTripTest struct { 136 h *Header 137 fm os.FileMode 138 } 139 140 func TestHeaderRoundTrip(t *testing.T) { 141 vectors := []headerRoundTripTest{{ 142 // regular file. 143 h: &Header{ 144 Name: "test.txt", 145 Mode: 0644 | c_ISREG, 146 Size: 12, 147 ModTime: time.Unix(1360600916, 0), 148 Typeflag: TypeReg, 149 }, 150 fm: 0644, 151 }, { 152 // symbolic link. 153 h: &Header{ 154 Name: "link.txt", 155 Mode: 0777 | c_ISLNK, 156 Size: 0, 157 ModTime: time.Unix(1360600852, 0), 158 Typeflag: TypeSymlink, 159 }, 160 fm: 0777 | os.ModeSymlink, 161 }, { 162 // character device node. 163 h: &Header{ 164 Name: "dev/null", 165 Mode: 0666 | c_ISCHR, 166 Size: 0, 167 ModTime: time.Unix(1360578951, 0), 168 Typeflag: TypeChar, 169 }, 170 fm: 0666 | os.ModeDevice | os.ModeCharDevice, 171 }, { 172 // block device node. 173 h: &Header{ 174 Name: "dev/sda", 175 Mode: 0660 | c_ISBLK, 176 Size: 0, 177 ModTime: time.Unix(1360578954, 0), 178 Typeflag: TypeBlock, 179 }, 180 fm: 0660 | os.ModeDevice, 181 }, { 182 // directory. 183 h: &Header{ 184 Name: "dir/", 185 Mode: 0755 | c_ISDIR, 186 Size: 0, 187 ModTime: time.Unix(1360601116, 0), 188 Typeflag: TypeDir, 189 }, 190 fm: 0755 | os.ModeDir, 191 }, { 192 // fifo node. 193 h: &Header{ 194 Name: "dev/initctl", 195 Mode: 0600 | c_ISFIFO, 196 Size: 0, 197 ModTime: time.Unix(1360578949, 0), 198 Typeflag: TypeFifo, 199 }, 200 fm: 0600 | os.ModeNamedPipe, 201 }, { 202 // setuid. 203 h: &Header{ 204 Name: "bin/su", 205 Mode: 0755 | c_ISREG | c_ISUID, 206 Size: 23232, 207 ModTime: time.Unix(1355405093, 0), 208 Typeflag: TypeReg, 209 }, 210 fm: 0755 | os.ModeSetuid, 211 }, { 212 // setguid. 213 h: &Header{ 214 Name: "group.txt", 215 Mode: 0750 | c_ISREG | c_ISGID, 216 Size: 0, 217 ModTime: time.Unix(1360602346, 0), 218 Typeflag: TypeReg, 219 }, 220 fm: 0750 | os.ModeSetgid, 221 }, { 222 // sticky. 223 h: &Header{ 224 Name: "sticky.txt", 225 Mode: 0600 | c_ISREG | c_ISVTX, 226 Size: 7, 227 ModTime: time.Unix(1360602540, 0), 228 Typeflag: TypeReg, 229 }, 230 fm: 0600 | os.ModeSticky, 231 }, { 232 // hard link. 233 h: &Header{ 234 Name: "hard.txt", 235 Mode: 0644 | c_ISREG, 236 Size: 0, 237 Linkname: "file.txt", 238 ModTime: time.Unix(1360600916, 0), 239 Typeflag: TypeLink, 240 }, 241 fm: 0644, 242 }, { 243 // More information. 244 h: &Header{ 245 Name: "info.txt", 246 Mode: 0600 | c_ISREG, 247 Size: 0, 248 Uid: 1000, 249 Gid: 1000, 250 ModTime: time.Unix(1360602540, 0), 251 Uname: "slartibartfast", 252 Gname: "users", 253 Typeflag: TypeReg, 254 }, 255 fm: 0600, 256 }} 257 258 for i, v := range vectors { 259 fi := v.h.FileInfo() 260 h2, err := FileInfoHeader(fi, "") 261 if err != nil { 262 t.Error(err) 263 continue 264 } 265 if strings.Contains(fi.Name(), "/") { 266 t.Errorf("FileInfo of %q contains slash: %q", v.h.Name, fi.Name()) 267 } 268 name := path.Base(v.h.Name) 269 if fi.IsDir() { 270 name += "/" 271 } 272 if got, want := h2.Name, name; got != want { 273 t.Errorf("i=%d: Name: got %v, want %v", i, got, want) 274 } 275 if got, want := h2.Size, v.h.Size; got != want { 276 t.Errorf("i=%d: Size: got %v, want %v", i, got, want) 277 } 278 if got, want := h2.Uid, v.h.Uid; got != want { 279 t.Errorf("i=%d: Uid: got %d, want %d", i, got, want) 280 } 281 if got, want := h2.Gid, v.h.Gid; got != want { 282 t.Errorf("i=%d: Gid: got %d, want %d", i, got, want) 283 } 284 if got, want := h2.Uname, v.h.Uname; got != want { 285 t.Errorf("i=%d: Uname: got %q, want %q", i, got, want) 286 } 287 if got, want := h2.Gname, v.h.Gname; got != want { 288 t.Errorf("i=%d: Gname: got %q, want %q", i, got, want) 289 } 290 if got, want := h2.Linkname, v.h.Linkname; got != want { 291 t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want) 292 } 293 if got, want := h2.Typeflag, v.h.Typeflag; got != want { 294 t.Logf("%#v %#v", v.h, fi.Sys()) 295 t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want) 296 } 297 if got, want := h2.Mode, v.h.Mode; got != want { 298 t.Errorf("i=%d: Mode: got %o, want %o", i, got, want) 299 } 300 if got, want := fi.Mode(), v.fm; got != want { 301 t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want) 302 } 303 if got, want := h2.AccessTime, v.h.AccessTime; got != want { 304 t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want) 305 } 306 if got, want := h2.ChangeTime, v.h.ChangeTime; got != want { 307 t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want) 308 } 309 if got, want := h2.ModTime, v.h.ModTime; got != want { 310 t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want) 311 } 312 if sysh, ok := fi.Sys().(*Header); !ok || sysh != v.h { 313 t.Errorf("i=%d: Sys didn't return original *Header", i) 314 } 315 } 316 }