mirror of
https://github.com/golang/go
synced 2024-11-18 15:34:53 -07:00
Add support for the basic extension done by Schilling's star.
Compute checksums in both ways (unsigned and signed). R=rsc APPROVED=rsc DELTA=188 (145 added, 21 deleted, 22 changed) OCL=30126 CL=30179
This commit is contained in:
parent
7fd9cfd0cc
commit
61d6ad3178
BIN
src/pkg/archive/tar/testdata/star.tar
vendored
Normal file
BIN
src/pkg/archive/tar/testdata/star.tar
vendored
Normal file
Binary file not shown.
@ -67,6 +67,8 @@ type Header struct {
|
|||||||
Gname string;
|
Gname string;
|
||||||
Devmajor int64;
|
Devmajor int64;
|
||||||
Devminor int64;
|
Devminor int64;
|
||||||
|
Atime int64;
|
||||||
|
Ctime int64;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *Reader) skipUnread()
|
func (tr *Reader) skipUnread()
|
||||||
@ -118,7 +120,10 @@ func cString(b []byte) string {
|
|||||||
return string(b[0:n])
|
return string(b[0:n])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *Reader) octalNumber(b []byte) int64 {
|
func (tr *Reader) octal(b []byte) int64 {
|
||||||
|
if len(b) > 0 && b[len(b)-1] == ' ' {
|
||||||
|
b = b[0:len(b)-1];
|
||||||
|
}
|
||||||
x, err := strconv.Btoui64(cString(b), 8);
|
x, err := strconv.Btoui64(cString(b), 8);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tr.err = err;
|
tr.err = err;
|
||||||
@ -149,23 +154,27 @@ func (tr *Reader) skipUnread() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tr *Reader) verifyChecksum(header []byte) bool {
|
func (tr *Reader) verifyChecksum(header []byte) bool {
|
||||||
given := tr.octalNumber(header[148:156]);
|
given := tr.octal(header[148:156]);
|
||||||
if tr.err != nil {
|
if tr.err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var computed int64;
|
// POSIX specifies a sum of the unsigned byte values,
|
||||||
|
// but the Sun tar uses signed byte values. :-(
|
||||||
|
var unsigned, signed int64;
|
||||||
for i := 0; i < len(header); i++ {
|
for i := 0; i < len(header); i++ {
|
||||||
if i == 148 {
|
if i == 148 {
|
||||||
// The chksum field is special: it should be treated as space bytes.
|
// The chksum field is special: it should be treated as space bytes.
|
||||||
computed += ' ' * 8;
|
unsigned += ' ' * 8;
|
||||||
|
signed += ' ' * 8;
|
||||||
i += 7;
|
i += 7;
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
computed += int64(header[i]);
|
unsigned += int64(header[i]);
|
||||||
|
signed += int64(int8(header[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return given == computed
|
return given == unsigned || given == signed
|
||||||
}
|
}
|
||||||
|
|
||||||
type slicer []byte
|
type slicer []byte
|
||||||
@ -205,15 +214,52 @@ func (tr *Reader) readHeader() *Header {
|
|||||||
// so use that value to do the correct parsing below.
|
// so use that value to do the correct parsing below.
|
||||||
|
|
||||||
hdr.Name = cString(s.next(100));
|
hdr.Name = cString(s.next(100));
|
||||||
hdr.Mode = tr.octalNumber(s.next(8));
|
hdr.Mode = tr.octal(s.next(8));
|
||||||
hdr.Uid = tr.octalNumber(s.next(8));
|
hdr.Uid = tr.octal(s.next(8));
|
||||||
hdr.Gid = tr.octalNumber(s.next(8));
|
hdr.Gid = tr.octal(s.next(8));
|
||||||
hdr.Size = tr.octalNumber(s.next(12));
|
hdr.Size = tr.octal(s.next(12));
|
||||||
hdr.Mtime = tr.octalNumber(s.next(12));
|
hdr.Mtime = tr.octal(s.next(12));
|
||||||
s.next(8); // chksum
|
s.next(8); // chksum
|
||||||
hdr.Typeflag = s.next(1)[0];
|
hdr.Typeflag = s.next(1)[0];
|
||||||
hdr.Linkname = cString(s.next(100));
|
hdr.Linkname = cString(s.next(100));
|
||||||
s.next(8); // magic, version
|
|
||||||
|
// The remainder of the header depends on the value of magic.
|
||||||
|
magic := string(s.next(8)); // contains version field as well.
|
||||||
|
var format string;
|
||||||
|
switch magic {
|
||||||
|
case "ustar\x0000": // POSIX tar (1003.1-1988)
|
||||||
|
if string(header[508:512]) == "tar\x00" {
|
||||||
|
format = "star";
|
||||||
|
} else {
|
||||||
|
format = "posix";
|
||||||
|
}
|
||||||
|
case "ustar \x00": // old GNU tar
|
||||||
|
format = "gnu";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch format {
|
||||||
|
case "posix", "gnu", "star":
|
||||||
|
hdr.Uname = cString(s.next(32));
|
||||||
|
hdr.Gname = cString(s.next(32));
|
||||||
|
devmajor := s.next(8);
|
||||||
|
devminor := s.next(8);
|
||||||
|
if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
|
||||||
|
hdr.Devmajor = tr.octal(devmajor);
|
||||||
|
hdr.Devminor = tr.octal(devminor);
|
||||||
|
}
|
||||||
|
var prefix string;
|
||||||
|
switch format {
|
||||||
|
case "posix", "gnu":
|
||||||
|
prefix = cString(s.next(155));
|
||||||
|
case "star":
|
||||||
|
prefix = cString(s.next(131));
|
||||||
|
hdr.Atime = tr.octal(s.next(12));
|
||||||
|
hdr.Ctime = tr.octal(s.next(12));
|
||||||
|
}
|
||||||
|
if len(prefix) > 0 {
|
||||||
|
hdr.Name = prefix + "/" + hdr.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if tr.err != nil {
|
if tr.err != nil {
|
||||||
tr.err = HeaderError;
|
tr.err = HeaderError;
|
||||||
|
@ -10,11 +10,107 @@ import (
|
|||||||
"fmt";
|
"fmt";
|
||||||
"io";
|
"io";
|
||||||
"os";
|
"os";
|
||||||
|
"reflect";
|
||||||
"testing";
|
"testing";
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUntar(t *testing.T) {
|
type untarTest struct {
|
||||||
f, err := os.Open("testdata/test.tar", os.O_RDONLY, 0444);
|
file string;
|
||||||
|
headers []*Header;
|
||||||
|
}
|
||||||
|
|
||||||
|
var untarTests = []*untarTest{
|
||||||
|
&untarTest{
|
||||||
|
file: "testdata/gnu.tar",
|
||||||
|
headers: []*Header{
|
||||||
|
&Header{
|
||||||
|
Name: "small.txt",
|
||||||
|
Mode: 0640,
|
||||||
|
Uid: 73025,
|
||||||
|
Gid: 5000,
|
||||||
|
Size: 5,
|
||||||
|
Mtime: 1244428340,
|
||||||
|
Typeflag: '0',
|
||||||
|
Uname: "dsymonds",
|
||||||
|
Gname: "eng",
|
||||||
|
},
|
||||||
|
&Header{
|
||||||
|
Name: "small2.txt",
|
||||||
|
Mode: 0640,
|
||||||
|
Uid: 73025,
|
||||||
|
Gid: 5000,
|
||||||
|
Size: 11,
|
||||||
|
Mtime: 1244436044,
|
||||||
|
Typeflag: '0',
|
||||||
|
Uname: "dsymonds",
|
||||||
|
Gname: "eng",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&untarTest{
|
||||||
|
file: "testdata/star.tar",
|
||||||
|
headers: []*Header{
|
||||||
|
&Header{
|
||||||
|
Name: "small.txt",
|
||||||
|
Mode: 0640,
|
||||||
|
Uid: 73025,
|
||||||
|
Gid: 5000,
|
||||||
|
Size: 5,
|
||||||
|
Mtime: 1244592783,
|
||||||
|
Typeflag: '0',
|
||||||
|
Uname: "dsymonds",
|
||||||
|
Gname: "eng",
|
||||||
|
Atime: 1244592783,
|
||||||
|
Ctime: 1244592783,
|
||||||
|
},
|
||||||
|
&Header{
|
||||||
|
Name: "small2.txt",
|
||||||
|
Mode: 0640,
|
||||||
|
Uid: 73025,
|
||||||
|
Gid: 5000,
|
||||||
|
Size: 11,
|
||||||
|
Mtime: 1244592783,
|
||||||
|
Typeflag: '0',
|
||||||
|
Uname: "dsymonds",
|
||||||
|
Gname: "eng",
|
||||||
|
Atime: 1244592783,
|
||||||
|
Ctime: 1244592783,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
func TestAll(t *testing.T) {
|
||||||
|
testLoop:
|
||||||
|
for i, test := range untarTests {
|
||||||
|
f, err := os.Open(test.file, os.O_RDONLY, 0444);
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("test %d: Unexpected error: %v", i, err);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tr := NewReader(f);
|
||||||
|
for j, header := range test.headers {
|
||||||
|
hdr, err := tr.Next();
|
||||||
|
if err != nil || hdr == nil {
|
||||||
|
t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err);
|
||||||
|
f.Close();
|
||||||
|
continue testLoop
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(hdr, header) {
|
||||||
|
t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
|
||||||
|
i, j, *hdr, *header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hdr, err := tr.Next();
|
||||||
|
if hdr != nil || err != nil {
|
||||||
|
t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, err);
|
||||||
|
}
|
||||||
|
f.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPartialRead(t *testing.T) {
|
||||||
|
f, err := os.Open("testdata/gnu.tar", os.O_RDONLY, 0444);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err);
|
t.Fatalf("Unexpected error: %v", err);
|
||||||
}
|
}
|
||||||
@ -22,22 +118,11 @@ func TestUntar(t *testing.T) {
|
|||||||
|
|
||||||
tr := NewReader(f);
|
tr := NewReader(f);
|
||||||
|
|
||||||
// First file
|
// Read the first four bytes; Next() should skip the last byte.
|
||||||
hdr, err := tr.Next();
|
hdr, err := tr.Next();
|
||||||
if err != nil || hdr == nil {
|
if err != nil || hdr == nil {
|
||||||
t.Fatalf("Didn't get first file: %v", err);
|
t.Fatalf("Didn't get first file: %v", err);
|
||||||
}
|
}
|
||||||
if hdr.Name != "small.txt" {
|
|
||||||
t.Errorf(`hdr.Name = %q, want "small.txt"`, hdr.Name);
|
|
||||||
}
|
|
||||||
if hdr.Mode != 0640 {
|
|
||||||
t.Errorf("hdr.Mode = %v, want 0640", hdr.Mode);
|
|
||||||
}
|
|
||||||
if hdr.Size != 5 {
|
|
||||||
t.Errorf("hdr.Size = %v, want 5", hdr.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the first four bytes; Next() should skip the last one.
|
|
||||||
buf := make([]byte, 4);
|
buf := make([]byte, 4);
|
||||||
if n, err := io.FullRead(tr, buf); err != nil {
|
if n, err := io.FullRead(tr, buf); err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err);
|
t.Fatalf("Unexpected error: %v", err);
|
||||||
@ -48,22 +133,14 @@ func TestUntar(t *testing.T) {
|
|||||||
|
|
||||||
// Second file
|
// Second file
|
||||||
hdr, err = tr.Next();
|
hdr, err = tr.Next();
|
||||||
if err != nil {
|
if err != nil || hdr == nil {
|
||||||
t.Fatalf("Didn't get second file: %v", err);
|
t.Fatalf("Didn't get second file: %v", err);
|
||||||
}
|
}
|
||||||
if hdr.Name != "small2.txt" {
|
buf = make([]byte, 6);
|
||||||
t.Errorf(`hdr.Name = %q, want "small2.txt"`, hdr.Name);
|
if n, err := io.FullRead(tr, buf); err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %v", err);
|
||||||
}
|
}
|
||||||
if hdr.Mode != 0640 {
|
if expected := io.StringBytes("Google"); !bytes.Equal(buf, expected) {
|
||||||
t.Errorf("hdr.Mode = %v, want 0640", hdr.Mode);
|
t.Errorf("Contents = %v, want %v", buf, expected);
|
||||||
}
|
|
||||||
if hdr.Size != 11 {
|
|
||||||
t.Errorf("hdr.Size = %v, want 11", hdr.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
hdr, err = tr.Next();
|
|
||||||
if hdr != nil || err != nil {
|
|
||||||
t.Fatalf("Unexpected third file or error: %v", err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user