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