Source file
src/archive/tar/writer_test.go
1
2
3
4
5 package tar
6
7 import (
8 "bytes"
9 "encoding/hex"
10 "errors"
11 "io"
12 "os"
13 "path"
14 "reflect"
15 "sort"
16 "strings"
17 "testing"
18 "testing/iotest"
19 "time"
20 )
21
22 func bytediff(a, b []byte) string {
23 const (
24 uniqueA = "- "
25 uniqueB = "+ "
26 identity = " "
27 )
28 var ss []string
29 sa := strings.Split(strings.TrimSpace(hex.Dump(a)), "\n")
30 sb := strings.Split(strings.TrimSpace(hex.Dump(b)), "\n")
31 for len(sa) > 0 && len(sb) > 0 {
32 if sa[0] == sb[0] {
33 ss = append(ss, identity+sa[0])
34 } else {
35 ss = append(ss, uniqueA+sa[0])
36 ss = append(ss, uniqueB+sb[0])
37 }
38 sa, sb = sa[1:], sb[1:]
39 }
40 for len(sa) > 0 {
41 ss = append(ss, uniqueA+sa[0])
42 sa = sa[1:]
43 }
44 for len(sb) > 0 {
45 ss = append(ss, uniqueB+sb[0])
46 sb = sb[1:]
47 }
48 return strings.Join(ss, "\n")
49 }
50
51 func TestWriter(t *testing.T) {
52 type (
53 testHeader struct {
54 hdr Header
55 wantErr error
56 }
57 testWrite struct {
58 str string
59 wantCnt int
60 wantErr error
61 }
62 testReadFrom struct {
63 ops fileOps
64 wantCnt int64
65 wantErr error
66 }
67 testClose struct {
68 wantErr error
69 }
70 testFnc interface{}
71 )
72
73 vectors := []struct {
74 file string
75 tests []testFnc
76 }{{
77
78
79
80
81 file: "testdata/writer.tar",
82 tests: []testFnc{
83 testHeader{Header{
84 Typeflag: TypeReg,
85 Name: "small.txt",
86 Size: 5,
87 Mode: 0640,
88 Uid: 73025,
89 Gid: 5000,
90 Uname: "dsymonds",
91 Gname: "eng",
92 ModTime: time.Unix(1246508266, 0),
93 }, nil},
94 testWrite{"Kilts", 5, nil},
95
96 testHeader{Header{
97 Typeflag: TypeReg,
98 Name: "small2.txt",
99 Size: 11,
100 Mode: 0640,
101 Uid: 73025,
102 Uname: "dsymonds",
103 Gname: "eng",
104 Gid: 5000,
105 ModTime: time.Unix(1245217492, 0),
106 }, nil},
107 testWrite{"Google.com\n", 11, nil},
108
109 testHeader{Header{
110 Typeflag: TypeSymlink,
111 Name: "link.txt",
112 Linkname: "small.txt",
113 Mode: 0777,
114 Uid: 1000,
115 Gid: 1000,
116 Uname: "strings",
117 Gname: "strings",
118 ModTime: time.Unix(1314603082, 0),
119 }, nil},
120 testWrite{"", 0, nil},
121
122 testClose{nil},
123 },
124 }, {
125
126
127
128 file: "testdata/writer-big.tar",
129 tests: []testFnc{
130 testHeader{Header{
131 Typeflag: TypeReg,
132 Name: "tmp/16gig.txt",
133 Size: 16 << 30,
134 Mode: 0640,
135 Uid: 73025,
136 Gid: 5000,
137 Uname: "dsymonds",
138 Gname: "eng",
139 ModTime: time.Unix(1254699560, 0),
140 Format: FormatGNU,
141 }, nil},
142 },
143 }, {
144
145
146
147
148
149
150
151 file: "testdata/writer-big-long.tar",
152 tests: []testFnc{
153 testHeader{Header{
154 Typeflag: TypeReg,
155 Name: strings.Repeat("longname/", 15) + "16gig.txt",
156 Size: 16 << 30,
157 Mode: 0644,
158 Uid: 1000,
159 Gid: 1000,
160 Uname: "guillaume",
161 Gname: "guillaume",
162 ModTime: time.Unix(1399583047, 0),
163 }, nil},
164 },
165 }, {
166
167
168 file: "testdata/ustar.tar",
169 tests: []testFnc{
170 testHeader{Header{
171 Typeflag: TypeReg,
172 Name: strings.Repeat("longname/", 15) + "file.txt",
173 Size: 6,
174 Mode: 0644,
175 Uid: 501,
176 Gid: 20,
177 Uname: "shane",
178 Gname: "staff",
179 ModTime: time.Unix(1360135598, 0),
180 }, nil},
181 testWrite{"hello\n", 6, nil},
182 testClose{nil},
183 },
184 }, {
185
186
187
188
189 file: "testdata/hardlink.tar",
190 tests: []testFnc{
191 testHeader{Header{
192 Typeflag: TypeReg,
193 Name: "file.txt",
194 Size: 15,
195 Mode: 0644,
196 Uid: 1000,
197 Gid: 100,
198 Uname: "vbatts",
199 Gname: "users",
200 ModTime: time.Unix(1425484303, 0),
201 }, nil},
202 testWrite{"Slartibartfast\n", 15, nil},
203
204 testHeader{Header{
205 Typeflag: TypeLink,
206 Name: "hard.txt",
207 Linkname: "file.txt",
208 Mode: 0644,
209 Uid: 1000,
210 Gid: 100,
211 Uname: "vbatts",
212 Gname: "users",
213 ModTime: time.Unix(1425484303, 0),
214 }, nil},
215 testWrite{"", 0, nil},
216
217 testClose{nil},
218 },
219 }, {
220 tests: []testFnc{
221 testHeader{Header{
222 Typeflag: TypeReg,
223 Name: "bad-null.txt",
224 Xattrs: map[string]string{"null\x00null\x00": "fizzbuzz"},
225 }, headerError{}},
226 },
227 }, {
228 tests: []testFnc{
229 testHeader{Header{
230 Typeflag: TypeReg,
231 Name: "null\x00.txt",
232 }, headerError{}},
233 },
234 }, {
235 file: "testdata/pax-records.tar",
236 tests: []testFnc{
237 testHeader{Header{
238 Typeflag: TypeReg,
239 Name: "file",
240 Uname: strings.Repeat("long", 10),
241 PAXRecords: map[string]string{
242 "path": "FILE",
243 "GNU.sparse.map": "0,0",
244 "comment": "Hello, 世界",
245 "GOLANG.pkg": "tar",
246 },
247 }, nil},
248 testClose{nil},
249 },
250 }, {
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281 file: "testdata/pax-global-records.tar",
282 tests: []testFnc{
283 testHeader{Header{
284 Typeflag: TypeXGlobalHeader,
285 PAXRecords: map[string]string{"path": "global1", "mtime": "1500000000.0"},
286 }, nil},
287 testHeader{Header{
288 Typeflag: TypeReg, Name: "file1",
289 }, nil},
290 testHeader{Header{
291 Typeflag: TypeReg,
292 Name: "file2",
293 PAXRecords: map[string]string{"path": "file2"},
294 }, nil},
295 testHeader{Header{
296 Typeflag: TypeXGlobalHeader,
297 PAXRecords: map[string]string{"path": ""},
298 }, nil},
299 testHeader{Header{
300 Typeflag: TypeReg, Name: "file3",
301 }, nil},
302 testHeader{Header{
303 Typeflag: TypeReg,
304 Name: "file4",
305 ModTime: time.Unix(1400000000, 0),
306 PAXRecords: map[string]string{"mtime": "1400000000"},
307 }, nil},
308 testClose{nil},
309 },
310 }, {
311 file: "testdata/gnu-utf8.tar",
312 tests: []testFnc{
313 testHeader{Header{
314 Typeflag: TypeReg,
315 Name: "☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹",
316 Mode: 0644,
317 Uid: 1000, Gid: 1000,
318 Uname: "☺",
319 Gname: "⚹",
320 ModTime: time.Unix(0, 0),
321 Format: FormatGNU,
322 }, nil},
323 testClose{nil},
324 },
325 }, {
326 file: "testdata/gnu-not-utf8.tar",
327 tests: []testFnc{
328 testHeader{Header{
329 Typeflag: TypeReg,
330 Name: "hi\x80\x81\x82\x83bye",
331 Mode: 0644,
332 Uid: 1000,
333 Gid: 1000,
334 Uname: "rawr",
335 Gname: "dsnet",
336 ModTime: time.Unix(0, 0),
337 Format: FormatGNU,
338 }, nil},
339 testClose{nil},
340 },
341
342
343
457 }, {
458 file: "testdata/trailing-slash.tar",
459 tests: []testFnc{
460 testHeader{Header{Name: strings.Repeat("123456789/", 30)}, nil},
461 testClose{nil},
462 },
463 }, {
464
465 file: "testdata/file-and-dir.tar",
466 tests: []testFnc{
467 testHeader{Header{Name: "small.txt", Size: 5}, nil},
468 testWrite{"Kilts", 5, nil},
469 testHeader{Header{Name: "dir/"}, nil},
470 testClose{nil},
471 },
472 }}
473
474 equalError := func(x, y error) bool {
475 _, ok1 := x.(headerError)
476 _, ok2 := y.(headerError)
477 if ok1 || ok2 {
478 return ok1 && ok2
479 }
480 return x == y
481 }
482 for _, v := range vectors {
483 t.Run(path.Base(v.file), func(t *testing.T) {
484 const maxSize = 10 << 10
485 buf := new(bytes.Buffer)
486 tw := NewWriter(iotest.TruncateWriter(buf, maxSize))
487
488 for i, tf := range v.tests {
489 switch tf := tf.(type) {
490 case testHeader:
491 err := tw.WriteHeader(&tf.hdr)
492 if !equalError(err, tf.wantErr) {
493 t.Fatalf("test %d, WriteHeader() = %v, want %v", i, err, tf.wantErr)
494 }
495 case testWrite:
496 got, err := tw.Write([]byte(tf.str))
497 if got != tf.wantCnt || !equalError(err, tf.wantErr) {
498 t.Fatalf("test %d, Write() = (%d, %v), want (%d, %v)", i, got, err, tf.wantCnt, tf.wantErr)
499 }
500 case testReadFrom:
501 f := &testFile{ops: tf.ops}
502 got, err := tw.readFrom(f)
503 if _, ok := err.(testError); ok {
504 t.Errorf("test %d, ReadFrom(): %v", i, err)
505 } else if got != tf.wantCnt || !equalError(err, tf.wantErr) {
506 t.Errorf("test %d, ReadFrom() = (%d, %v), want (%d, %v)", i, got, err, tf.wantCnt, tf.wantErr)
507 }
508 if len(f.ops) > 0 {
509 t.Errorf("test %d, expected %d more operations", i, len(f.ops))
510 }
511 case testClose:
512 err := tw.Close()
513 if !equalError(err, tf.wantErr) {
514 t.Fatalf("test %d, Close() = %v, want %v", i, err, tf.wantErr)
515 }
516 default:
517 t.Fatalf("test %d, unknown test operation: %T", i, tf)
518 }
519 }
520
521 if v.file != "" {
522 want, err := os.ReadFile(v.file)
523 if err != nil {
524 t.Fatalf("ReadFile() = %v, want nil", err)
525 }
526 got := buf.Bytes()
527 if !bytes.Equal(want, got) {
528 t.Fatalf("incorrect result: (-got +want)\n%v", bytediff(got, want))
529 }
530 }
531 })
532 }
533 }
534
535 func TestPax(t *testing.T) {
536
537 fileinfo, err := os.Stat("testdata/small.txt")
538 if err != nil {
539 t.Fatal(err)
540 }
541 hdr, err := FileInfoHeader(fileinfo, "")
542 if err != nil {
543 t.Fatalf("os.Stat: %v", err)
544 }
545
546 longName := strings.Repeat("ab", 100)
547 contents := strings.Repeat(" ", int(hdr.Size))
548 hdr.Name = longName
549 var buf bytes.Buffer
550 writer := NewWriter(&buf)
551 if err := writer.WriteHeader(hdr); err != nil {
552 t.Fatal(err)
553 }
554 if _, err = writer.Write([]byte(contents)); err != nil {
555 t.Fatal(err)
556 }
557 if err := writer.Close(); err != nil {
558 t.Fatal(err)
559 }
560
561 if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
562 t.Fatal("Expected at least one PAX header to be written.")
563 }
564
565 reader := NewReader(&buf)
566 hdr, err = reader.Next()
567 if err != nil {
568 t.Fatal(err)
569 }
570 if hdr.Name != longName {
571 t.Fatal("Couldn't recover long file name")
572 }
573 }
574
575 func TestPaxSymlink(t *testing.T) {
576
577 fileinfo, err := os.Stat("testdata/small.txt")
578 if err != nil {
579 t.Fatal(err)
580 }
581 hdr, err := FileInfoHeader(fileinfo, "")
582 hdr.Typeflag = TypeSymlink
583 if err != nil {
584 t.Fatalf("os.Stat:1 %v", err)
585 }
586
587 longLinkname := strings.Repeat("1234567890/1234567890", 10)
588 hdr.Linkname = longLinkname
589
590 hdr.Size = 0
591 var buf bytes.Buffer
592 writer := NewWriter(&buf)
593 if err := writer.WriteHeader(hdr); err != nil {
594 t.Fatal(err)
595 }
596 if err := writer.Close(); err != nil {
597 t.Fatal(err)
598 }
599
600 if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
601 t.Fatal("Expected at least one PAX header to be written.")
602 }
603
604 reader := NewReader(&buf)
605 hdr, err = reader.Next()
606 if err != nil {
607 t.Fatal(err)
608 }
609 if hdr.Linkname != longLinkname {
610 t.Fatal("Couldn't recover long link name")
611 }
612 }
613
614 func TestPaxNonAscii(t *testing.T) {
615
616
617 fileinfo, err := os.Stat("testdata/small.txt")
618 if err != nil {
619 t.Fatal(err)
620 }
621
622 hdr, err := FileInfoHeader(fileinfo, "")
623 if err != nil {
624 t.Fatalf("os.Stat:1 %v", err)
625 }
626
627
628 chineseFilename := "文件名"
629 chineseGroupname := "組"
630 chineseUsername := "用戶名"
631
632 hdr.Name = chineseFilename
633 hdr.Gname = chineseGroupname
634 hdr.Uname = chineseUsername
635
636 contents := strings.Repeat(" ", int(hdr.Size))
637
638 var buf bytes.Buffer
639 writer := NewWriter(&buf)
640 if err := writer.WriteHeader(hdr); err != nil {
641 t.Fatal(err)
642 }
643 if _, err = writer.Write([]byte(contents)); err != nil {
644 t.Fatal(err)
645 }
646 if err := writer.Close(); err != nil {
647 t.Fatal(err)
648 }
649
650 if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
651 t.Fatal("Expected at least one PAX header to be written.")
652 }
653
654 reader := NewReader(&buf)
655 hdr, err = reader.Next()
656 if err != nil {
657 t.Fatal(err)
658 }
659 if hdr.Name != chineseFilename {
660 t.Fatal("Couldn't recover unicode name")
661 }
662 if hdr.Gname != chineseGroupname {
663 t.Fatal("Couldn't recover unicode group")
664 }
665 if hdr.Uname != chineseUsername {
666 t.Fatal("Couldn't recover unicode user")
667 }
668 }
669
670 func TestPaxXattrs(t *testing.T) {
671 xattrs := map[string]string{
672 "user.key": "value",
673 }
674
675
676 fileinfo, err := os.Stat("testdata/small.txt")
677 if err != nil {
678 t.Fatal(err)
679 }
680 hdr, err := FileInfoHeader(fileinfo, "")
681 if err != nil {
682 t.Fatalf("os.Stat: %v", err)
683 }
684 contents := "Kilts"
685 hdr.Xattrs = xattrs
686 var buf bytes.Buffer
687 writer := NewWriter(&buf)
688 if err := writer.WriteHeader(hdr); err != nil {
689 t.Fatal(err)
690 }
691 if _, err = writer.Write([]byte(contents)); err != nil {
692 t.Fatal(err)
693 }
694 if err := writer.Close(); err != nil {
695 t.Fatal(err)
696 }
697
698 reader := NewReader(&buf)
699 hdr, err = reader.Next()
700 if err != nil {
701 t.Fatal(err)
702 }
703 if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
704 t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
705 hdr.Xattrs, xattrs)
706 }
707 }
708
709 func TestPaxHeadersSorted(t *testing.T) {
710 fileinfo, err := os.Stat("testdata/small.txt")
711 if err != nil {
712 t.Fatal(err)
713 }
714 hdr, err := FileInfoHeader(fileinfo, "")
715 if err != nil {
716 t.Fatalf("os.Stat: %v", err)
717 }
718 contents := strings.Repeat(" ", int(hdr.Size))
719
720 hdr.Xattrs = map[string]string{
721 "foo": "foo",
722 "bar": "bar",
723 "baz": "baz",
724 "qux": "qux",
725 }
726
727 var buf bytes.Buffer
728 writer := NewWriter(&buf)
729 if err := writer.WriteHeader(hdr); err != nil {
730 t.Fatal(err)
731 }
732 if _, err = writer.Write([]byte(contents)); err != nil {
733 t.Fatal(err)
734 }
735 if err := writer.Close(); err != nil {
736 t.Fatal(err)
737 }
738
739 if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
740 t.Fatal("Expected at least one PAX header to be written.")
741 }
742
743
744 indices := []int{
745 bytes.Index(buf.Bytes(), []byte("bar=bar")),
746 bytes.Index(buf.Bytes(), []byte("baz=baz")),
747 bytes.Index(buf.Bytes(), []byte("foo=foo")),
748 bytes.Index(buf.Bytes(), []byte("qux=qux")),
749 }
750 if !sort.IntsAreSorted(indices) {
751 t.Fatal("PAX headers are not sorted")
752 }
753 }
754
755 func TestUSTARLongName(t *testing.T) {
756
757 fileinfo, err := os.Stat("testdata/small.txt")
758 if err != nil {
759 t.Fatal(err)
760 }
761 hdr, err := FileInfoHeader(fileinfo, "")
762 hdr.Typeflag = TypeDir
763 if err != nil {
764 t.Fatalf("os.Stat:1 %v", err)
765 }
766
767
768 longName := "/0000_0000000/00000-000000000/0000_0000000/00000-0000000000000/0000_0000000/00000-0000000-00000000/0000_0000000/00000000/0000_0000000/000/0000_0000000/00000000v00/0000_0000000/000000/0000_0000000/0000000/0000_0000000/00000y-00/0000/0000/00000000/0x000000/"
769 hdr.Name = longName
770
771 hdr.Size = 0
772 var buf bytes.Buffer
773 writer := NewWriter(&buf)
774 if err := writer.WriteHeader(hdr); err != nil {
775 t.Fatal(err)
776 }
777 if err := writer.Close(); err != nil {
778 t.Fatal(err)
779 }
780
781 reader := NewReader(&buf)
782 hdr, err = reader.Next()
783 if err != nil {
784 t.Fatal(err)
785 }
786 if hdr.Name != longName {
787 t.Fatal("Couldn't recover long name")
788 }
789 }
790
791 func TestValidTypeflagWithPAXHeader(t *testing.T) {
792 var buffer bytes.Buffer
793 tw := NewWriter(&buffer)
794
795 fileName := strings.Repeat("ab", 100)
796
797 hdr := &Header{
798 Name: fileName,
799 Size: 4,
800 Typeflag: 0,
801 }
802 if err := tw.WriteHeader(hdr); err != nil {
803 t.Fatalf("Failed to write header: %s", err)
804 }
805 if _, err := tw.Write([]byte("fooo")); err != nil {
806 t.Fatalf("Failed to write the file's data: %s", err)
807 }
808 tw.Close()
809
810 tr := NewReader(&buffer)
811
812 for {
813 header, err := tr.Next()
814 if err == io.EOF {
815 break
816 }
817 if err != nil {
818 t.Fatalf("Failed to read header: %s", err)
819 }
820 if header.Typeflag != TypeReg {
821 t.Fatalf("Typeflag should've been %d, found %d", TypeReg, header.Typeflag)
822 }
823 }
824 }
825
826
827 type failOnceWriter bool
828
829 func (w *failOnceWriter) Write(b []byte) (int, error) {
830 if !*w {
831 return 0, io.ErrShortWrite
832 }
833 *w = true
834 return len(b), nil
835 }
836
837 func TestWriterErrors(t *testing.T) {
838 t.Run("HeaderOnly", func(t *testing.T) {
839 tw := NewWriter(new(bytes.Buffer))
840 hdr := &Header{Name: "dir/", Typeflag: TypeDir}
841 if err := tw.WriteHeader(hdr); err != nil {
842 t.Fatalf("WriteHeader() = %v, want nil", err)
843 }
844 if _, err := tw.Write([]byte{0x00}); err != ErrWriteTooLong {
845 t.Fatalf("Write() = %v, want %v", err, ErrWriteTooLong)
846 }
847 })
848
849 t.Run("NegativeSize", func(t *testing.T) {
850 tw := NewWriter(new(bytes.Buffer))
851 hdr := &Header{Name: "small.txt", Size: -1}
852 if err := tw.WriteHeader(hdr); err == nil {
853 t.Fatalf("WriteHeader() = nil, want non-nil error")
854 }
855 })
856
857 t.Run("BeforeHeader", func(t *testing.T) {
858 tw := NewWriter(new(bytes.Buffer))
859 if _, err := tw.Write([]byte("Kilts")); err != ErrWriteTooLong {
860 t.Fatalf("Write() = %v, want %v", err, ErrWriteTooLong)
861 }
862 })
863
864 t.Run("AfterClose", func(t *testing.T) {
865 tw := NewWriter(new(bytes.Buffer))
866 hdr := &Header{Name: "small.txt"}
867 if err := tw.WriteHeader(hdr); err != nil {
868 t.Fatalf("WriteHeader() = %v, want nil", err)
869 }
870 if err := tw.Close(); err != nil {
871 t.Fatalf("Close() = %v, want nil", err)
872 }
873 if _, err := tw.Write([]byte("Kilts")); err != ErrWriteAfterClose {
874 t.Fatalf("Write() = %v, want %v", err, ErrWriteAfterClose)
875 }
876 if err := tw.Flush(); err != ErrWriteAfterClose {
877 t.Fatalf("Flush() = %v, want %v", err, ErrWriteAfterClose)
878 }
879 if err := tw.Close(); err != nil {
880 t.Fatalf("Close() = %v, want nil", err)
881 }
882 })
883
884 t.Run("PrematureFlush", func(t *testing.T) {
885 tw := NewWriter(new(bytes.Buffer))
886 hdr := &Header{Name: "small.txt", Size: 5}
887 if err := tw.WriteHeader(hdr); err != nil {
888 t.Fatalf("WriteHeader() = %v, want nil", err)
889 }
890 if err := tw.Flush(); err == nil {
891 t.Fatalf("Flush() = %v, want non-nil error", err)
892 }
893 })
894
895 t.Run("PrematureClose", func(t *testing.T) {
896 tw := NewWriter(new(bytes.Buffer))
897 hdr := &Header{Name: "small.txt", Size: 5}
898 if err := tw.WriteHeader(hdr); err != nil {
899 t.Fatalf("WriteHeader() = %v, want nil", err)
900 }
901 if err := tw.Close(); err == nil {
902 t.Fatalf("Close() = %v, want non-nil error", err)
903 }
904 })
905
906 t.Run("Persistence", func(t *testing.T) {
907 tw := NewWriter(new(failOnceWriter))
908 if err := tw.WriteHeader(&Header{}); err != io.ErrShortWrite {
909 t.Fatalf("WriteHeader() = %v, want %v", err, io.ErrShortWrite)
910 }
911 if err := tw.WriteHeader(&Header{Name: "small.txt"}); err == nil {
912 t.Errorf("WriteHeader() = got %v, want non-nil error", err)
913 }
914 if _, err := tw.Write(nil); err == nil {
915 t.Errorf("Write() = %v, want non-nil error", err)
916 }
917 if err := tw.Flush(); err == nil {
918 t.Errorf("Flush() = %v, want non-nil error", err)
919 }
920 if err := tw.Close(); err == nil {
921 t.Errorf("Close() = %v, want non-nil error", err)
922 }
923 })
924 }
925
926 func TestSplitUSTARPath(t *testing.T) {
927 sr := strings.Repeat
928
929 vectors := []struct {
930 input string
931 prefix string
932 suffix string
933 ok bool
934 }{
935 {"", "", "", false},
936 {"abc", "", "", false},
937 {"用戶名", "", "", false},
938 {sr("a", nameSize), "", "", false},
939 {sr("a", nameSize) + "/", "", "", false},
940 {sr("a", nameSize) + "/a", sr("a", nameSize), "a", true},
941 {sr("a", prefixSize) + "/", "", "", false},
942 {sr("a", prefixSize) + "/a", sr("a", prefixSize), "a", true},
943 {sr("a", nameSize+1), "", "", false},
944 {sr("/", nameSize+1), sr("/", nameSize-1), "/", true},
945 {sr("a", prefixSize) + "/" + sr("b", nameSize),
946 sr("a", prefixSize), sr("b", nameSize), true},
947 {sr("a", prefixSize) + "//" + sr("b", nameSize), "", "", false},
948 {sr("a/", nameSize), sr("a/", 77) + "a", sr("a/", 22), true},
949 }
950
951 for _, v := range vectors {
952 prefix, suffix, ok := splitUSTARPath(v.input)
953 if prefix != v.prefix || suffix != v.suffix || ok != v.ok {
954 t.Errorf("splitUSTARPath(%q):\ngot (%q, %q, %v)\nwant (%q, %q, %v)",
955 v.input, prefix, suffix, ok, v.prefix, v.suffix, v.ok)
956 }
957 }
958 }
959
960
961
962
963 func TestIssue12594(t *testing.T) {
964 names := []string{
965 "0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/file.txt",
966 "0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/file.txt",
967 "0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/333/file.txt",
968 "0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/file.txt",
969 "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000/file.txt",
970 "/home/support/.openoffice.org/3/user/uno_packages/cache/registry/com.sun.star.comp.deployment.executable.PackageRegistryBackend",
971 }
972
973 for i, name := range names {
974 var b bytes.Buffer
975
976 tw := NewWriter(&b)
977 if err := tw.WriteHeader(&Header{
978 Name: name,
979 Uid: 1 << 25,
980 }); err != nil {
981 t.Errorf("test %d, unexpected WriteHeader error: %v", i, err)
982 }
983 if err := tw.Close(); err != nil {
984 t.Errorf("test %d, unexpected Close error: %v", i, err)
985 }
986
987
988 var blk block
989 copy(blk[:], b.Bytes())
990 prefix := string(blk.USTAR().Prefix())
991 if i := strings.IndexByte(prefix, 0); i >= 0 {
992 prefix = prefix[:i]
993 }
994 if blk.GetFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
995 t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
996 }
997
998 tr := NewReader(&b)
999 hdr, err := tr.Next()
1000 if err != nil {
1001 t.Errorf("test %d, unexpected Next error: %v", i, err)
1002 }
1003 if hdr.Name != name {
1004 t.Errorf("test %d, hdr.Name = %s, want %s", i, hdr.Name, name)
1005 }
1006 }
1007 }
1008
1009
1010
1011 type testNonEmptyWriter struct{ io.Writer }
1012
1013 func (w testNonEmptyWriter) Write(b []byte) (int, error) {
1014 if len(b) == 0 {
1015 return 0, errors.New("unexpected empty Write call")
1016 }
1017 return w.Writer.Write(b)
1018 }
1019
1020 func TestFileWriter(t *testing.T) {
1021 type (
1022 testWrite struct {
1023 str string
1024 wantCnt int
1025 wantErr error
1026 }
1027 testReadFrom struct {
1028 ops fileOps
1029 wantCnt int64
1030 wantErr error
1031 }
1032 testRemaining struct {
1033 wantLCnt int64
1034 wantPCnt int64
1035 }
1036 testFnc interface{}
1037 )
1038
1039 type (
1040 makeReg struct {
1041 size int64
1042 wantStr string
1043 }
1044 makeSparse struct {
1045 makeReg makeReg
1046 sph sparseHoles
1047 size int64
1048 }
1049 fileMaker interface{}
1050 )
1051
1052 vectors := []struct {
1053 maker fileMaker
1054 tests []testFnc
1055 }{{
1056 maker: makeReg{0, ""},
1057 tests: []testFnc{
1058 testRemaining{0, 0},
1059 testWrite{"", 0, nil},
1060 testWrite{"a", 0, ErrWriteTooLong},
1061 testReadFrom{fileOps{""}, 0, nil},
1062 testReadFrom{fileOps{"a"}, 0, ErrWriteTooLong},
1063 testRemaining{0, 0},
1064 },
1065 }, {
1066 maker: makeReg{1, "a"},
1067 tests: []testFnc{
1068 testRemaining{1, 1},
1069 testWrite{"", 0, nil},
1070 testWrite{"a", 1, nil},
1071 testWrite{"bcde", 0, ErrWriteTooLong},
1072 testWrite{"", 0, nil},
1073 testReadFrom{fileOps{""}, 0, nil},
1074 testReadFrom{fileOps{"a"}, 0, ErrWriteTooLong},
1075 testRemaining{0, 0},
1076 },
1077 }, {
1078 maker: makeReg{5, "hello"},
1079 tests: []testFnc{
1080 testRemaining{5, 5},
1081 testWrite{"hello", 5, nil},
1082 testRemaining{0, 0},
1083 },
1084 }, {
1085 maker: makeReg{5, "\x00\x00\x00\x00\x00"},
1086 tests: []testFnc{
1087 testRemaining{5, 5},
1088 testReadFrom{fileOps{"\x00\x00\x00\x00\x00"}, 5, nil},
1089 testRemaining{0, 0},
1090 },
1091 }, {
1092 maker: makeReg{5, "\x00\x00\x00\x00\x00"},
1093 tests: []testFnc{
1094 testRemaining{5, 5},
1095 testReadFrom{fileOps{"\x00\x00\x00\x00\x00extra"}, 5, ErrWriteTooLong},
1096 testRemaining{0, 0},
1097 },
1098 }, {
1099 maker: makeReg{5, "abc\x00\x00"},
1100 tests: []testFnc{
1101 testRemaining{5, 5},
1102 testWrite{"abc", 3, nil},
1103 testRemaining{2, 2},
1104 testReadFrom{fileOps{"\x00\x00"}, 2, nil},
1105 testRemaining{0, 0},
1106 },
1107 }, {
1108 maker: makeReg{5, "\x00\x00abc"},
1109 tests: []testFnc{
1110 testRemaining{5, 5},
1111 testWrite{"\x00\x00", 2, nil},
1112 testRemaining{3, 3},
1113 testWrite{"abc", 3, nil},
1114 testReadFrom{fileOps{"z"}, 0, ErrWriteTooLong},
1115 testWrite{"z", 0, ErrWriteTooLong},
1116 testRemaining{0, 0},
1117 },
1118 }, {
1119 maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
1120 tests: []testFnc{
1121 testRemaining{8, 5},
1122 testWrite{"ab\x00\x00\x00cde", 8, nil},
1123 testWrite{"a", 0, ErrWriteTooLong},
1124 testRemaining{0, 0},
1125 },
1126 }, {
1127 maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
1128 tests: []testFnc{
1129 testWrite{"ab\x00\x00\x00cdez", 8, ErrWriteTooLong},
1130 testRemaining{0, 0},
1131 },
1132 }, {
1133 maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
1134 tests: []testFnc{
1135 testWrite{"ab\x00", 3, nil},
1136 testRemaining{5, 3},
1137 testWrite{"\x00\x00cde", 5, nil},
1138 testWrite{"a", 0, ErrWriteTooLong},
1139 testRemaining{0, 0},
1140 },
1141 }, {
1142 maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
1143 tests: []testFnc{
1144 testWrite{"ab", 2, nil},
1145 testRemaining{6, 3},
1146 testReadFrom{fileOps{int64(3), "cde"}, 6, nil},
1147 testRemaining{0, 0},
1148 },
1149 }, {
1150 maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
1151 tests: []testFnc{
1152 testReadFrom{fileOps{"ab", int64(3), "cde"}, 8, nil},
1153 testRemaining{0, 0},
1154 },
1155 }, {
1156 maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
1157 tests: []testFnc{
1158 testReadFrom{fileOps{"ab", int64(3), "cdeX"}, 8, ErrWriteTooLong},
1159 testRemaining{0, 0},
1160 },
1161 }, {
1162 maker: makeSparse{makeReg{4, "abcd"}, sparseHoles{{2, 3}}, 8},
1163 tests: []testFnc{
1164 testReadFrom{fileOps{"ab", int64(3), "cd"}, 7, io.ErrUnexpectedEOF},
1165 testRemaining{1, 0},
1166 },
1167 }, {
1168 maker: makeSparse{makeReg{4, "abcd"}, sparseHoles{{2, 3}}, 8},
1169 tests: []testFnc{
1170 testReadFrom{fileOps{"ab", int64(3), "cde"}, 7, errMissData},
1171 testRemaining{1, 0},
1172 },
1173 }, {
1174 maker: makeSparse{makeReg{6, "abcde"}, sparseHoles{{2, 3}}, 8},
1175 tests: []testFnc{
1176 testReadFrom{fileOps{"ab", int64(3), "cde"}, 8, errUnrefData},
1177 testRemaining{0, 1},
1178 },
1179 }, {
1180 maker: makeSparse{makeReg{4, "abcd"}, sparseHoles{{2, 3}}, 8},
1181 tests: []testFnc{
1182 testWrite{"ab", 2, nil},
1183 testRemaining{6, 2},
1184 testWrite{"\x00\x00\x00", 3, nil},
1185 testRemaining{3, 2},
1186 testWrite{"cde", 2, errMissData},
1187 testRemaining{1, 0},
1188 },
1189 }, {
1190 maker: makeSparse{makeReg{6, "abcde"}, sparseHoles{{2, 3}}, 8},
1191 tests: []testFnc{
1192 testWrite{"ab", 2, nil},
1193 testRemaining{6, 4},
1194 testWrite{"\x00\x00\x00", 3, nil},
1195 testRemaining{3, 4},
1196 testWrite{"cde", 3, errUnrefData},
1197 testRemaining{0, 1},
1198 },
1199 }, {
1200 maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
1201 tests: []testFnc{
1202 testRemaining{7, 3},
1203 testWrite{"\x00\x00abc\x00\x00", 7, nil},
1204 testRemaining{0, 0},
1205 },
1206 }, {
1207 maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
1208 tests: []testFnc{
1209 testRemaining{7, 3},
1210 testReadFrom{fileOps{int64(2), "abc", int64(1), "\x00"}, 7, nil},
1211 testRemaining{0, 0},
1212 },
1213 }, {
1214 maker: makeSparse{makeReg{3, ""}, sparseHoles{{0, 2}, {5, 2}}, 7},
1215 tests: []testFnc{
1216 testWrite{"abcdefg", 0, errWriteHole},
1217 },
1218 }, {
1219 maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
1220 tests: []testFnc{
1221 testWrite{"\x00\x00abcde", 5, errWriteHole},
1222 },
1223 }, {
1224 maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
1225 tests: []testFnc{
1226 testWrite{"\x00\x00abc\x00\x00z", 7, ErrWriteTooLong},
1227 testRemaining{0, 0},
1228 },
1229 }, {
1230 maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
1231 tests: []testFnc{
1232 testWrite{"\x00\x00", 2, nil},
1233 testRemaining{5, 3},
1234 testWrite{"abc", 3, nil},
1235 testRemaining{2, 0},
1236 testWrite{"\x00\x00", 2, nil},
1237 testRemaining{0, 0},
1238 },
1239 }, {
1240 maker: makeSparse{makeReg{2, "ab"}, sparseHoles{{0, 2}, {5, 2}}, 7},
1241 tests: []testFnc{
1242 testWrite{"\x00\x00", 2, nil},
1243 testWrite{"abc", 2, errMissData},
1244 testWrite{"\x00\x00", 0, errMissData},
1245 },
1246 }, {
1247 maker: makeSparse{makeReg{4, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
1248 tests: []testFnc{
1249 testWrite{"\x00\x00", 2, nil},
1250 testWrite{"abc", 3, nil},
1251 testWrite{"\x00\x00", 2, errUnrefData},
1252 },
1253 }}
1254
1255 for i, v := range vectors {
1256 var wantStr string
1257 bb := new(bytes.Buffer)
1258 w := testNonEmptyWriter{bb}
1259 var fw fileWriter
1260 switch maker := v.maker.(type) {
1261 case makeReg:
1262 fw = ®FileWriter{w, maker.size}
1263 wantStr = maker.wantStr
1264 case makeSparse:
1265 if !validateSparseEntries(maker.sph, maker.size) {
1266 t.Fatalf("invalid sparse map: %v", maker.sph)
1267 }
1268 spd := invertSparseEntries(maker.sph, maker.size)
1269 fw = ®FileWriter{w, maker.makeReg.size}
1270 fw = &sparseFileWriter{fw, spd, 0}
1271 wantStr = maker.makeReg.wantStr
1272 default:
1273 t.Fatalf("test %d, unknown make operation: %T", i, maker)
1274 }
1275
1276 for j, tf := range v.tests {
1277 switch tf := tf.(type) {
1278 case testWrite:
1279 got, err := fw.Write([]byte(tf.str))
1280 if got != tf.wantCnt || err != tf.wantErr {
1281 t.Errorf("test %d.%d, Write(%s):\ngot (%d, %v)\nwant (%d, %v)", i, j, tf.str, got, err, tf.wantCnt, tf.wantErr)
1282 }
1283 case testReadFrom:
1284 f := &testFile{ops: tf.ops}
1285 got, err := fw.ReadFrom(f)
1286 if _, ok := err.(testError); ok {
1287 t.Errorf("test %d.%d, ReadFrom(): %v", i, j, err)
1288 } else if got != tf.wantCnt || err != tf.wantErr {
1289 t.Errorf("test %d.%d, ReadFrom() = (%d, %v), want (%d, %v)", i, j, got, err, tf.wantCnt, tf.wantErr)
1290 }
1291 if len(f.ops) > 0 {
1292 t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops))
1293 }
1294 case testRemaining:
1295 if got := fw.LogicalRemaining(); got != tf.wantLCnt {
1296 t.Errorf("test %d.%d, LogicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
1297 }
1298 if got := fw.PhysicalRemaining(); got != tf.wantPCnt {
1299 t.Errorf("test %d.%d, PhysicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
1300 }
1301 default:
1302 t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)
1303 }
1304 }
1305
1306 if got := bb.String(); got != wantStr {
1307 t.Fatalf("test %d, String() = %q, want %q", i, got, wantStr)
1308 }
1309 }
1310 }
1311
View as plain text