github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/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())|c_ISREG; 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())|c_ISDIR; 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 | c_ISREG,
   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 | c_ISLNK,
   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 | c_ISCHR,
   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 | c_ISBLK,
   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 | c_ISDIR,
   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 | c_ISFIFO,
   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_ISREG | 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_ISREG | 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_ISREG | 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 | c_ISREG,
   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 | c_ISREG,
   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  }