Signed-off-by: Darren Stahl <darst@microsoft.com>
| ... | ... |
@@ -30,7 +30,7 @@ github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8 |
| 30 | 30 |
github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2 |
| 31 | 31 |
|
| 32 | 32 |
#get libnetwork packages |
| 33 |
-github.com/docker/libnetwork 68f1039f172434709a4550fe92e3e058406c74ce |
|
| 33 |
+github.com/docker/libnetwork 72fd7e5495eba86e28012e39b5ed63ef9ca9a97b |
|
| 34 | 34 |
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 |
| 35 | 35 |
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 |
| 36 | 36 |
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec |
| 37 | 37 |
deleted file mode 100644 |
| ... | ... |
@@ -1,80 +0,0 @@ |
| 1 |
-// Copyright 2013 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_test |
|
| 6 |
- |
|
| 7 |
-import ( |
|
| 8 |
- "archive/tar" |
|
| 9 |
- "bytes" |
|
| 10 |
- "fmt" |
|
| 11 |
- "io" |
|
| 12 |
- "log" |
|
| 13 |
- "os" |
|
| 14 |
-) |
|
| 15 |
- |
|
| 16 |
-func Example() {
|
|
| 17 |
- // Create a buffer to write our archive to. |
|
| 18 |
- buf := new(bytes.Buffer) |
|
| 19 |
- |
|
| 20 |
- // Create a new tar archive. |
|
| 21 |
- tw := tar.NewWriter(buf) |
|
| 22 |
- |
|
| 23 |
- // Add some files to the archive. |
|
| 24 |
- var files = []struct {
|
|
| 25 |
- Name, Body string |
|
| 26 |
- }{
|
|
| 27 |
- {"readme.txt", "This archive contains some text files."},
|
|
| 28 |
- {"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
|
|
| 29 |
- {"todo.txt", "Get animal handling license."},
|
|
| 30 |
- } |
|
| 31 |
- for _, file := range files {
|
|
| 32 |
- hdr := &tar.Header{
|
|
| 33 |
- Name: file.Name, |
|
| 34 |
- Mode: 0600, |
|
| 35 |
- Size: int64(len(file.Body)), |
|
| 36 |
- } |
|
| 37 |
- if err := tw.WriteHeader(hdr); err != nil {
|
|
| 38 |
- log.Fatalln(err) |
|
| 39 |
- } |
|
| 40 |
- if _, err := tw.Write([]byte(file.Body)); err != nil {
|
|
| 41 |
- log.Fatalln(err) |
|
| 42 |
- } |
|
| 43 |
- } |
|
| 44 |
- // Make sure to check the error on Close. |
|
| 45 |
- if err := tw.Close(); err != nil {
|
|
| 46 |
- log.Fatalln(err) |
|
| 47 |
- } |
|
| 48 |
- |
|
| 49 |
- // Open the tar archive for reading. |
|
| 50 |
- r := bytes.NewReader(buf.Bytes()) |
|
| 51 |
- tr := tar.NewReader(r) |
|
| 52 |
- |
|
| 53 |
- // Iterate through the files in the archive. |
|
| 54 |
- for {
|
|
| 55 |
- hdr, err := tr.Next() |
|
| 56 |
- if err == io.EOF {
|
|
| 57 |
- // end of tar archive |
|
| 58 |
- break |
|
| 59 |
- } |
|
| 60 |
- if err != nil {
|
|
| 61 |
- log.Fatalln(err) |
|
| 62 |
- } |
|
| 63 |
- fmt.Printf("Contents of %s:\n", hdr.Name)
|
|
| 64 |
- if _, err := io.Copy(os.Stdout, tr); err != nil {
|
|
| 65 |
- log.Fatalln(err) |
|
| 66 |
- } |
|
| 67 |
- fmt.Println() |
|
| 68 |
- } |
|
| 69 |
- |
|
| 70 |
- // Output: |
|
| 71 |
- // Contents of readme.txt: |
|
| 72 |
- // This archive contains some text files. |
|
| 73 |
- // Contents of gopher.txt: |
|
| 74 |
- // Gopher names: |
|
| 75 |
- // George |
|
| 76 |
- // Geoffrey |
|
| 77 |
- // Gonzo |
|
| 78 |
- // Contents of todo.txt: |
|
| 79 |
- // Get animal handling license. |
|
| 80 |
-} |
| 81 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,1054 +0,0 @@ |
| 1 |
-// Copyright 2009 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 |
- "crypto/md5" |
|
| 10 |
- "fmt" |
|
| 11 |
- "io" |
|
| 12 |
- "io/ioutil" |
|
| 13 |
- "math" |
|
| 14 |
- "os" |
|
| 15 |
- "reflect" |
|
| 16 |
- "strings" |
|
| 17 |
- "testing" |
|
| 18 |
- "time" |
|
| 19 |
-) |
|
| 20 |
- |
|
| 21 |
-func TestReader(t *testing.T) {
|
|
| 22 |
- vectors := []struct {
|
|
| 23 |
- file string // Test input file |
|
| 24 |
- headers []*Header // Expected output headers |
|
| 25 |
- chksums []string // MD5 checksum of files, leave as nil if not checked |
|
| 26 |
- err error // Expected error to occur |
|
| 27 |
- }{{
|
|
| 28 |
- file: "testdata/gnu.tar", |
|
| 29 |
- headers: []*Header{{
|
|
| 30 |
- Name: "small.txt", |
|
| 31 |
- Mode: 0640, |
|
| 32 |
- Uid: 73025, |
|
| 33 |
- Gid: 5000, |
|
| 34 |
- Size: 5, |
|
| 35 |
- ModTime: time.Unix(1244428340, 0), |
|
| 36 |
- Typeflag: '0', |
|
| 37 |
- Uname: "dsymonds", |
|
| 38 |
- Gname: "eng", |
|
| 39 |
- }, {
|
|
| 40 |
- Name: "small2.txt", |
|
| 41 |
- Mode: 0640, |
|
| 42 |
- Uid: 73025, |
|
| 43 |
- Gid: 5000, |
|
| 44 |
- Size: 11, |
|
| 45 |
- ModTime: time.Unix(1244436044, 0), |
|
| 46 |
- Typeflag: '0', |
|
| 47 |
- Uname: "dsymonds", |
|
| 48 |
- Gname: "eng", |
|
| 49 |
- }}, |
|
| 50 |
- chksums: []string{
|
|
| 51 |
- "e38b27eaccb4391bdec553a7f3ae6b2f", |
|
| 52 |
- "c65bd2e50a56a2138bf1716f2fd56fe9", |
|
| 53 |
- }, |
|
| 54 |
- }, {
|
|
| 55 |
- file: "testdata/sparse-formats.tar", |
|
| 56 |
- headers: []*Header{{
|
|
| 57 |
- Name: "sparse-gnu", |
|
| 58 |
- Mode: 420, |
|
| 59 |
- Uid: 1000, |
|
| 60 |
- Gid: 1000, |
|
| 61 |
- Size: 200, |
|
| 62 |
- ModTime: time.Unix(1392395740, 0), |
|
| 63 |
- Typeflag: 0x53, |
|
| 64 |
- Linkname: "", |
|
| 65 |
- Uname: "david", |
|
| 66 |
- Gname: "david", |
|
| 67 |
- Devmajor: 0, |
|
| 68 |
- Devminor: 0, |
|
| 69 |
- }, {
|
|
| 70 |
- Name: "sparse-posix-0.0", |
|
| 71 |
- Mode: 420, |
|
| 72 |
- Uid: 1000, |
|
| 73 |
- Gid: 1000, |
|
| 74 |
- Size: 200, |
|
| 75 |
- ModTime: time.Unix(1392342187, 0), |
|
| 76 |
- Typeflag: 0x30, |
|
| 77 |
- Linkname: "", |
|
| 78 |
- Uname: "david", |
|
| 79 |
- Gname: "david", |
|
| 80 |
- Devmajor: 0, |
|
| 81 |
- Devminor: 0, |
|
| 82 |
- }, {
|
|
| 83 |
- Name: "sparse-posix-0.1", |
|
| 84 |
- Mode: 420, |
|
| 85 |
- Uid: 1000, |
|
| 86 |
- Gid: 1000, |
|
| 87 |
- Size: 200, |
|
| 88 |
- ModTime: time.Unix(1392340456, 0), |
|
| 89 |
- Typeflag: 0x30, |
|
| 90 |
- Linkname: "", |
|
| 91 |
- Uname: "david", |
|
| 92 |
- Gname: "david", |
|
| 93 |
- Devmajor: 0, |
|
| 94 |
- Devminor: 0, |
|
| 95 |
- }, {
|
|
| 96 |
- Name: "sparse-posix-1.0", |
|
| 97 |
- Mode: 420, |
|
| 98 |
- Uid: 1000, |
|
| 99 |
- Gid: 1000, |
|
| 100 |
- Size: 200, |
|
| 101 |
- ModTime: time.Unix(1392337404, 0), |
|
| 102 |
- Typeflag: 0x30, |
|
| 103 |
- Linkname: "", |
|
| 104 |
- Uname: "david", |
|
| 105 |
- Gname: "david", |
|
| 106 |
- Devmajor: 0, |
|
| 107 |
- Devminor: 0, |
|
| 108 |
- }, {
|
|
| 109 |
- Name: "end", |
|
| 110 |
- Mode: 420, |
|
| 111 |
- Uid: 1000, |
|
| 112 |
- Gid: 1000, |
|
| 113 |
- Size: 4, |
|
| 114 |
- ModTime: time.Unix(1392398319, 0), |
|
| 115 |
- Typeflag: 0x30, |
|
| 116 |
- Linkname: "", |
|
| 117 |
- Uname: "david", |
|
| 118 |
- Gname: "david", |
|
| 119 |
- Devmajor: 0, |
|
| 120 |
- Devminor: 0, |
|
| 121 |
- }}, |
|
| 122 |
- chksums: []string{
|
|
| 123 |
- "6f53234398c2449fe67c1812d993012f", |
|
| 124 |
- "6f53234398c2449fe67c1812d993012f", |
|
| 125 |
- "6f53234398c2449fe67c1812d993012f", |
|
| 126 |
- "6f53234398c2449fe67c1812d993012f", |
|
| 127 |
- "b0061974914468de549a2af8ced10316", |
|
| 128 |
- }, |
|
| 129 |
- }, {
|
|
| 130 |
- file: "testdata/star.tar", |
|
| 131 |
- headers: []*Header{{
|
|
| 132 |
- Name: "small.txt", |
|
| 133 |
- Mode: 0640, |
|
| 134 |
- Uid: 73025, |
|
| 135 |
- Gid: 5000, |
|
| 136 |
- Size: 5, |
|
| 137 |
- ModTime: time.Unix(1244592783, 0), |
|
| 138 |
- Typeflag: '0', |
|
| 139 |
- Uname: "dsymonds", |
|
| 140 |
- Gname: "eng", |
|
| 141 |
- AccessTime: time.Unix(1244592783, 0), |
|
| 142 |
- ChangeTime: time.Unix(1244592783, 0), |
|
| 143 |
- }, {
|
|
| 144 |
- Name: "small2.txt", |
|
| 145 |
- Mode: 0640, |
|
| 146 |
- Uid: 73025, |
|
| 147 |
- Gid: 5000, |
|
| 148 |
- Size: 11, |
|
| 149 |
- ModTime: time.Unix(1244592783, 0), |
|
| 150 |
- Typeflag: '0', |
|
| 151 |
- Uname: "dsymonds", |
|
| 152 |
- Gname: "eng", |
|
| 153 |
- AccessTime: time.Unix(1244592783, 0), |
|
| 154 |
- ChangeTime: time.Unix(1244592783, 0), |
|
| 155 |
- }}, |
|
| 156 |
- }, {
|
|
| 157 |
- file: "testdata/v7.tar", |
|
| 158 |
- headers: []*Header{{
|
|
| 159 |
- Name: "small.txt", |
|
| 160 |
- Mode: 0444, |
|
| 161 |
- Uid: 73025, |
|
| 162 |
- Gid: 5000, |
|
| 163 |
- Size: 5, |
|
| 164 |
- ModTime: time.Unix(1244593104, 0), |
|
| 165 |
- Typeflag: '\x00', |
|
| 166 |
- }, {
|
|
| 167 |
- Name: "small2.txt", |
|
| 168 |
- Mode: 0444, |
|
| 169 |
- Uid: 73025, |
|
| 170 |
- Gid: 5000, |
|
| 171 |
- Size: 11, |
|
| 172 |
- ModTime: time.Unix(1244593104, 0), |
|
| 173 |
- Typeflag: '\x00', |
|
| 174 |
- }}, |
|
| 175 |
- }, {
|
|
| 176 |
- file: "testdata/pax.tar", |
|
| 177 |
- headers: []*Header{{
|
|
| 178 |
- Name: "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100", |
|
| 179 |
- Mode: 0664, |
|
| 180 |
- Uid: 1000, |
|
| 181 |
- Gid: 1000, |
|
| 182 |
- Uname: "shane", |
|
| 183 |
- Gname: "shane", |
|
| 184 |
- Size: 7, |
|
| 185 |
- ModTime: time.Unix(1350244992, 23960108), |
|
| 186 |
- ChangeTime: time.Unix(1350244992, 23960108), |
|
| 187 |
- AccessTime: time.Unix(1350244992, 23960108), |
|
| 188 |
- Typeflag: TypeReg, |
|
| 189 |
- }, {
|
|
| 190 |
- Name: "a/b", |
|
| 191 |
- Mode: 0777, |
|
| 192 |
- Uid: 1000, |
|
| 193 |
- Gid: 1000, |
|
| 194 |
- Uname: "shane", |
|
| 195 |
- Gname: "shane", |
|
| 196 |
- Size: 0, |
|
| 197 |
- ModTime: time.Unix(1350266320, 910238425), |
|
| 198 |
- ChangeTime: time.Unix(1350266320, 910238425), |
|
| 199 |
- AccessTime: time.Unix(1350266320, 910238425), |
|
| 200 |
- Typeflag: TypeSymlink, |
|
| 201 |
- Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100", |
|
| 202 |
- }}, |
|
| 203 |
- }, {
|
|
| 204 |
- file: "testdata/pax-bad-hdr-file.tar", |
|
| 205 |
- err: ErrHeader, |
|
| 206 |
- }, {
|
|
| 207 |
- file: "testdata/pax-bad-mtime-file.tar", |
|
| 208 |
- err: ErrHeader, |
|
| 209 |
- }, {
|
|
| 210 |
- file: "testdata/pax-pos-size-file.tar", |
|
| 211 |
- headers: []*Header{{
|
|
| 212 |
- Name: "foo", |
|
| 213 |
- Mode: 0640, |
|
| 214 |
- Uid: 319973, |
|
| 215 |
- Gid: 5000, |
|
| 216 |
- Size: 999, |
|
| 217 |
- ModTime: time.Unix(1442282516, 0), |
|
| 218 |
- Typeflag: '0', |
|
| 219 |
- Uname: "joetsai", |
|
| 220 |
- Gname: "eng", |
|
| 221 |
- }}, |
|
| 222 |
- chksums: []string{
|
|
| 223 |
- "0afb597b283fe61b5d4879669a350556", |
|
| 224 |
- }, |
|
| 225 |
- }, {
|
|
| 226 |
- file: "testdata/nil-uid.tar", // golang.org/issue/5290 |
|
| 227 |
- headers: []*Header{{
|
|
| 228 |
- Name: "P1050238.JPG.log", |
|
| 229 |
- Mode: 0664, |
|
| 230 |
- Uid: 0, |
|
| 231 |
- Gid: 0, |
|
| 232 |
- Size: 14, |
|
| 233 |
- ModTime: time.Unix(1365454838, 0), |
|
| 234 |
- Typeflag: TypeReg, |
|
| 235 |
- Linkname: "", |
|
| 236 |
- Uname: "eyefi", |
|
| 237 |
- Gname: "eyefi", |
|
| 238 |
- Devmajor: 0, |
|
| 239 |
- Devminor: 0, |
|
| 240 |
- }}, |
|
| 241 |
- }, {
|
|
| 242 |
- file: "testdata/xattrs.tar", |
|
| 243 |
- headers: []*Header{{
|
|
| 244 |
- Name: "small.txt", |
|
| 245 |
- Mode: 0644, |
|
| 246 |
- Uid: 1000, |
|
| 247 |
- Gid: 10, |
|
| 248 |
- Size: 5, |
|
| 249 |
- ModTime: time.Unix(1386065770, 448252320), |
|
| 250 |
- Typeflag: '0', |
|
| 251 |
- Uname: "alex", |
|
| 252 |
- Gname: "wheel", |
|
| 253 |
- AccessTime: time.Unix(1389782991, 419875220), |
|
| 254 |
- ChangeTime: time.Unix(1389782956, 794414986), |
|
| 255 |
- Xattrs: map[string]string{
|
|
| 256 |
- "user.key": "value", |
|
| 257 |
- "user.key2": "value2", |
|
| 258 |
- // Interestingly, selinux encodes the terminating null inside the xattr |
|
| 259 |
- "security.selinux": "unconfined_u:object_r:default_t:s0\x00", |
|
| 260 |
- }, |
|
| 261 |
- }, {
|
|
| 262 |
- Name: "small2.txt", |
|
| 263 |
- Mode: 0644, |
|
| 264 |
- Uid: 1000, |
|
| 265 |
- Gid: 10, |
|
| 266 |
- Size: 11, |
|
| 267 |
- ModTime: time.Unix(1386065770, 449252304), |
|
| 268 |
- Typeflag: '0', |
|
| 269 |
- Uname: "alex", |
|
| 270 |
- Gname: "wheel", |
|
| 271 |
- AccessTime: time.Unix(1389782991, 419875220), |
|
| 272 |
- ChangeTime: time.Unix(1386065770, 449252304), |
|
| 273 |
- Xattrs: map[string]string{
|
|
| 274 |
- "security.selinux": "unconfined_u:object_r:default_t:s0\x00", |
|
| 275 |
- }, |
|
| 276 |
- }}, |
|
| 277 |
- }, {
|
|
| 278 |
- // Matches the behavior of GNU, BSD, and STAR tar utilities. |
|
| 279 |
- file: "testdata/gnu-multi-hdrs.tar", |
|
| 280 |
- headers: []*Header{{
|
|
| 281 |
- Name: "GNU2/GNU2/long-path-name", |
|
| 282 |
- Linkname: "GNU4/GNU4/long-linkpath-name", |
|
| 283 |
- ModTime: time.Unix(0, 0), |
|
| 284 |
- Typeflag: '2', |
|
| 285 |
- }}, |
|
| 286 |
- }, {
|
|
| 287 |
- // Matches the behavior of GNU and BSD tar utilities. |
|
| 288 |
- file: "testdata/pax-multi-hdrs.tar", |
|
| 289 |
- headers: []*Header{{
|
|
| 290 |
- Name: "bar", |
|
| 291 |
- Linkname: "PAX4/PAX4/long-linkpath-name", |
|
| 292 |
- ModTime: time.Unix(0, 0), |
|
| 293 |
- Typeflag: '2', |
|
| 294 |
- }}, |
|
| 295 |
- }, {
|
|
| 296 |
- file: "testdata/neg-size.tar", |
|
| 297 |
- err: ErrHeader, |
|
| 298 |
- }, {
|
|
| 299 |
- file: "testdata/issue10968.tar", |
|
| 300 |
- err: ErrHeader, |
|
| 301 |
- }, {
|
|
| 302 |
- file: "testdata/issue11169.tar", |
|
| 303 |
- err: ErrHeader, |
|
| 304 |
- }, {
|
|
| 305 |
- file: "testdata/issue12435.tar", |
|
| 306 |
- err: ErrHeader, |
|
| 307 |
- }} |
|
| 308 |
- |
|
| 309 |
- for i, v := range vectors {
|
|
| 310 |
- f, err := os.Open(v.file) |
|
| 311 |
- if err != nil {
|
|
| 312 |
- t.Errorf("file %s, test %d: unexpected error: %v", v.file, i, err)
|
|
| 313 |
- continue |
|
| 314 |
- } |
|
| 315 |
- defer f.Close() |
|
| 316 |
- |
|
| 317 |
- // Capture all headers and checksums. |
|
| 318 |
- var ( |
|
| 319 |
- tr = NewReader(f) |
|
| 320 |
- hdrs []*Header |
|
| 321 |
- chksums []string |
|
| 322 |
- rdbuf = make([]byte, 8) |
|
| 323 |
- ) |
|
| 324 |
- for {
|
|
| 325 |
- var hdr *Header |
|
| 326 |
- hdr, err = tr.Next() |
|
| 327 |
- if err != nil {
|
|
| 328 |
- if err == io.EOF {
|
|
| 329 |
- err = nil // Expected error |
|
| 330 |
- } |
|
| 331 |
- break |
|
| 332 |
- } |
|
| 333 |
- hdrs = append(hdrs, hdr) |
|
| 334 |
- |
|
| 335 |
- if v.chksums == nil {
|
|
| 336 |
- continue |
|
| 337 |
- } |
|
| 338 |
- h := md5.New() |
|
| 339 |
- _, err = io.CopyBuffer(h, tr, rdbuf) // Effectively an incremental read |
|
| 340 |
- if err != nil {
|
|
| 341 |
- break |
|
| 342 |
- } |
|
| 343 |
- chksums = append(chksums, fmt.Sprintf("%x", h.Sum(nil)))
|
|
| 344 |
- } |
|
| 345 |
- |
|
| 346 |
- for j, hdr := range hdrs {
|
|
| 347 |
- if j >= len(v.headers) {
|
|
| 348 |
- t.Errorf("file %s, test %d, entry %d: unexpected header:\ngot %+v",
|
|
| 349 |
- v.file, i, j, *hdr) |
|
| 350 |
- continue |
|
| 351 |
- } |
|
| 352 |
- if !reflect.DeepEqual(*hdr, *v.headers[j]) {
|
|
| 353 |
- t.Errorf("file %s, test %d, entry %d: incorrect header:\ngot %+v\nwant %+v",
|
|
| 354 |
- v.file, i, j, *hdr, *v.headers[j]) |
|
| 355 |
- } |
|
| 356 |
- } |
|
| 357 |
- if len(hdrs) != len(v.headers) {
|
|
| 358 |
- t.Errorf("file %s, test %d: got %d headers, want %d headers",
|
|
| 359 |
- v.file, i, len(hdrs), len(v.headers)) |
|
| 360 |
- } |
|
| 361 |
- |
|
| 362 |
- for j, sum := range chksums {
|
|
| 363 |
- if j >= len(v.chksums) {
|
|
| 364 |
- t.Errorf("file %s, test %d, entry %d: unexpected sum: got %s",
|
|
| 365 |
- v.file, i, j, sum) |
|
| 366 |
- continue |
|
| 367 |
- } |
|
| 368 |
- if sum != v.chksums[j] {
|
|
| 369 |
- t.Errorf("file %s, test %d, entry %d: incorrect checksum: got %s, want %s",
|
|
| 370 |
- v.file, i, j, sum, v.chksums[j]) |
|
| 371 |
- } |
|
| 372 |
- } |
|
| 373 |
- |
|
| 374 |
- if err != v.err {
|
|
| 375 |
- t.Errorf("file %s, test %d: unexpected error: got %v, want %v",
|
|
| 376 |
- v.file, i, err, v.err) |
|
| 377 |
- } |
|
| 378 |
- f.Close() |
|
| 379 |
- } |
|
| 380 |
-} |
|
| 381 |
- |
|
| 382 |
-func TestPartialRead(t *testing.T) {
|
|
| 383 |
- f, err := os.Open("testdata/gnu.tar")
|
|
| 384 |
- if err != nil {
|
|
| 385 |
- t.Fatalf("Unexpected error: %v", err)
|
|
| 386 |
- } |
|
| 387 |
- defer f.Close() |
|
| 388 |
- |
|
| 389 |
- tr := NewReader(f) |
|
| 390 |
- |
|
| 391 |
- // Read the first four bytes; Next() should skip the last byte. |
|
| 392 |
- hdr, err := tr.Next() |
|
| 393 |
- if err != nil || hdr == nil {
|
|
| 394 |
- t.Fatalf("Didn't get first file: %v", err)
|
|
| 395 |
- } |
|
| 396 |
- buf := make([]byte, 4) |
|
| 397 |
- if _, err := io.ReadFull(tr, buf); err != nil {
|
|
| 398 |
- t.Fatalf("Unexpected error: %v", err)
|
|
| 399 |
- } |
|
| 400 |
- if expected := []byte("Kilt"); !bytes.Equal(buf, expected) {
|
|
| 401 |
- t.Errorf("Contents = %v, want %v", buf, expected)
|
|
| 402 |
- } |
|
| 403 |
- |
|
| 404 |
- // Second file |
|
| 405 |
- hdr, err = tr.Next() |
|
| 406 |
- if err != nil || hdr == nil {
|
|
| 407 |
- t.Fatalf("Didn't get second file: %v", err)
|
|
| 408 |
- } |
|
| 409 |
- buf = make([]byte, 6) |
|
| 410 |
- if _, err := io.ReadFull(tr, buf); err != nil {
|
|
| 411 |
- t.Fatalf("Unexpected error: %v", err)
|
|
| 412 |
- } |
|
| 413 |
- if expected := []byte("Google"); !bytes.Equal(buf, expected) {
|
|
| 414 |
- t.Errorf("Contents = %v, want %v", buf, expected)
|
|
| 415 |
- } |
|
| 416 |
-} |
|
| 417 |
- |
|
| 418 |
-func TestSparseFileReader(t *testing.T) {
|
|
| 419 |
- vectors := []struct {
|
|
| 420 |
- realSize int64 // Real size of the output file |
|
| 421 |
- sparseMap []sparseEntry // Input sparse map |
|
| 422 |
- sparseData string // Input compact data |
|
| 423 |
- expected string // Expected output data |
|
| 424 |
- err error // Expected error outcome |
|
| 425 |
- }{{
|
|
| 426 |
- realSize: 8, |
|
| 427 |
- sparseMap: []sparseEntry{
|
|
| 428 |
- {offset: 0, numBytes: 2},
|
|
| 429 |
- {offset: 5, numBytes: 3},
|
|
| 430 |
- }, |
|
| 431 |
- sparseData: "abcde", |
|
| 432 |
- expected: "ab\x00\x00\x00cde", |
|
| 433 |
- }, {
|
|
| 434 |
- realSize: 10, |
|
| 435 |
- sparseMap: []sparseEntry{
|
|
| 436 |
- {offset: 0, numBytes: 2},
|
|
| 437 |
- {offset: 5, numBytes: 3},
|
|
| 438 |
- }, |
|
| 439 |
- sparseData: "abcde", |
|
| 440 |
- expected: "ab\x00\x00\x00cde\x00\x00", |
|
| 441 |
- }, {
|
|
| 442 |
- realSize: 8, |
|
| 443 |
- sparseMap: []sparseEntry{
|
|
| 444 |
- {offset: 1, numBytes: 3},
|
|
| 445 |
- {offset: 6, numBytes: 2},
|
|
| 446 |
- }, |
|
| 447 |
- sparseData: "abcde", |
|
| 448 |
- expected: "\x00abc\x00\x00de", |
|
| 449 |
- }, {
|
|
| 450 |
- realSize: 8, |
|
| 451 |
- sparseMap: []sparseEntry{
|
|
| 452 |
- {offset: 1, numBytes: 3},
|
|
| 453 |
- {offset: 6, numBytes: 0},
|
|
| 454 |
- {offset: 6, numBytes: 0},
|
|
| 455 |
- {offset: 6, numBytes: 2},
|
|
| 456 |
- }, |
|
| 457 |
- sparseData: "abcde", |
|
| 458 |
- expected: "\x00abc\x00\x00de", |
|
| 459 |
- }, {
|
|
| 460 |
- realSize: 10, |
|
| 461 |
- sparseMap: []sparseEntry{
|
|
| 462 |
- {offset: 1, numBytes: 3},
|
|
| 463 |
- {offset: 6, numBytes: 2},
|
|
| 464 |
- }, |
|
| 465 |
- sparseData: "abcde", |
|
| 466 |
- expected: "\x00abc\x00\x00de\x00\x00", |
|
| 467 |
- }, {
|
|
| 468 |
- realSize: 10, |
|
| 469 |
- sparseMap: []sparseEntry{
|
|
| 470 |
- {offset: 1, numBytes: 3},
|
|
| 471 |
- {offset: 6, numBytes: 2},
|
|
| 472 |
- {offset: 8, numBytes: 0},
|
|
| 473 |
- {offset: 8, numBytes: 0},
|
|
| 474 |
- {offset: 8, numBytes: 0},
|
|
| 475 |
- {offset: 8, numBytes: 0},
|
|
| 476 |
- }, |
|
| 477 |
- sparseData: "abcde", |
|
| 478 |
- expected: "\x00abc\x00\x00de\x00\x00", |
|
| 479 |
- }, {
|
|
| 480 |
- realSize: 2, |
|
| 481 |
- sparseMap: []sparseEntry{},
|
|
| 482 |
- sparseData: "", |
|
| 483 |
- expected: "\x00\x00", |
|
| 484 |
- }, {
|
|
| 485 |
- realSize: -2, |
|
| 486 |
- sparseMap: []sparseEntry{},
|
|
| 487 |
- err: ErrHeader, |
|
| 488 |
- }, {
|
|
| 489 |
- realSize: -10, |
|
| 490 |
- sparseMap: []sparseEntry{
|
|
| 491 |
- {offset: 1, numBytes: 3},
|
|
| 492 |
- {offset: 6, numBytes: 2},
|
|
| 493 |
- }, |
|
| 494 |
- sparseData: "abcde", |
|
| 495 |
- err: ErrHeader, |
|
| 496 |
- }, {
|
|
| 497 |
- realSize: 10, |
|
| 498 |
- sparseMap: []sparseEntry{
|
|
| 499 |
- {offset: 1, numBytes: 3},
|
|
| 500 |
- {offset: 6, numBytes: 5},
|
|
| 501 |
- }, |
|
| 502 |
- sparseData: "abcde", |
|
| 503 |
- err: ErrHeader, |
|
| 504 |
- }, {
|
|
| 505 |
- realSize: 35, |
|
| 506 |
- sparseMap: []sparseEntry{
|
|
| 507 |
- {offset: 1, numBytes: 3},
|
|
| 508 |
- {offset: 6, numBytes: 5},
|
|
| 509 |
- }, |
|
| 510 |
- sparseData: "abcde", |
|
| 511 |
- err: io.ErrUnexpectedEOF, |
|
| 512 |
- }, {
|
|
| 513 |
- realSize: 35, |
|
| 514 |
- sparseMap: []sparseEntry{
|
|
| 515 |
- {offset: 1, numBytes: 3},
|
|
| 516 |
- {offset: 6, numBytes: -5},
|
|
| 517 |
- }, |
|
| 518 |
- sparseData: "abcde", |
|
| 519 |
- err: ErrHeader, |
|
| 520 |
- }, {
|
|
| 521 |
- realSize: 35, |
|
| 522 |
- sparseMap: []sparseEntry{
|
|
| 523 |
- {offset: math.MaxInt64, numBytes: 3},
|
|
| 524 |
- {offset: 6, numBytes: -5},
|
|
| 525 |
- }, |
|
| 526 |
- sparseData: "abcde", |
|
| 527 |
- err: ErrHeader, |
|
| 528 |
- }, {
|
|
| 529 |
- realSize: 10, |
|
| 530 |
- sparseMap: []sparseEntry{
|
|
| 531 |
- {offset: 1, numBytes: 3},
|
|
| 532 |
- {offset: 2, numBytes: 2},
|
|
| 533 |
- }, |
|
| 534 |
- sparseData: "abcde", |
|
| 535 |
- err: ErrHeader, |
|
| 536 |
- }} |
|
| 537 |
- |
|
| 538 |
- for i, v := range vectors {
|
|
| 539 |
- r := bytes.NewReader([]byte(v.sparseData)) |
|
| 540 |
- rfr := ®FileReader{r: r, nb: int64(len(v.sparseData))}
|
|
| 541 |
- |
|
| 542 |
- var ( |
|
| 543 |
- sfr *sparseFileReader |
|
| 544 |
- err error |
|
| 545 |
- buf []byte |
|
| 546 |
- ) |
|
| 547 |
- |
|
| 548 |
- sfr, err = newSparseFileReader(rfr, v.sparseMap, v.realSize) |
|
| 549 |
- if err != nil {
|
|
| 550 |
- goto fail |
|
| 551 |
- } |
|
| 552 |
- if sfr.numBytes() != int64(len(v.sparseData)) {
|
|
| 553 |
- t.Errorf("test %d, numBytes() before reading: got %d, want %d", i, sfr.numBytes(), len(v.sparseData))
|
|
| 554 |
- } |
|
| 555 |
- buf, err = ioutil.ReadAll(sfr) |
|
| 556 |
- if err != nil {
|
|
| 557 |
- goto fail |
|
| 558 |
- } |
|
| 559 |
- if string(buf) != v.expected {
|
|
| 560 |
- t.Errorf("test %d, ReadAll(): got %q, want %q", i, string(buf), v.expected)
|
|
| 561 |
- } |
|
| 562 |
- if sfr.numBytes() != 0 {
|
|
| 563 |
- t.Errorf("test %d, numBytes() after reading: got %d, want %d", i, sfr.numBytes(), 0)
|
|
| 564 |
- } |
|
| 565 |
- |
|
| 566 |
- fail: |
|
| 567 |
- if err != v.err {
|
|
| 568 |
- t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
|
|
| 569 |
- } |
|
| 570 |
- } |
|
| 571 |
-} |
|
| 572 |
- |
|
| 573 |
-func TestReadOldGNUSparseMap(t *testing.T) {
|
|
| 574 |
- const ( |
|
| 575 |
- t00 = "00000000000\x0000000000000\x00" |
|
| 576 |
- t11 = "00000000001\x0000000000001\x00" |
|
| 577 |
- t12 = "00000000001\x0000000000002\x00" |
|
| 578 |
- t21 = "00000000002\x0000000000001\x00" |
|
| 579 |
- ) |
|
| 580 |
- |
|
| 581 |
- mkBlk := func(size, sp0, sp1, sp2, sp3, ext string, format int) *block {
|
|
| 582 |
- var blk block |
|
| 583 |
- copy(blk.GNU().RealSize(), size) |
|
| 584 |
- copy(blk.GNU().Sparse().Entry(0), sp0) |
|
| 585 |
- copy(blk.GNU().Sparse().Entry(1), sp1) |
|
| 586 |
- copy(blk.GNU().Sparse().Entry(2), sp2) |
|
| 587 |
- copy(blk.GNU().Sparse().Entry(3), sp3) |
|
| 588 |
- copy(blk.GNU().Sparse().IsExtended(), ext) |
|
| 589 |
- if format != formatUnknown {
|
|
| 590 |
- blk.SetFormat(format) |
|
| 591 |
- } |
|
| 592 |
- return &blk |
|
| 593 |
- } |
|
| 594 |
- |
|
| 595 |
- vectors := []struct {
|
|
| 596 |
- data string // Input data |
|
| 597 |
- rawHdr *block // Input raw header |
|
| 598 |
- want []sparseEntry // Expected sparse entries to be outputted |
|
| 599 |
- err error // Expected error to be returned |
|
| 600 |
- }{
|
|
| 601 |
- {"", mkBlk("", "", "", "", "", "", formatUnknown), nil, ErrHeader},
|
|
| 602 |
- {"", mkBlk("1234", "fewa", "", "", "", "", formatGNU), nil, ErrHeader},
|
|
| 603 |
- {"", mkBlk("0031", "", "", "", "", "", formatGNU), nil, nil},
|
|
| 604 |
- {"", mkBlk("1234", t00, t11, "", "", "", formatGNU),
|
|
| 605 |
- []sparseEntry{{0, 0}, {1, 1}}, nil},
|
|
| 606 |
- {"", mkBlk("1234", t11, t12, t21, t11, "", formatGNU),
|
|
| 607 |
- []sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}}, nil},
|
|
| 608 |
- {"", mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
|
|
| 609 |
- []sparseEntry{}, io.ErrUnexpectedEOF},
|
|
| 610 |
- {t11 + t11,
|
|
| 611 |
- mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
|
|
| 612 |
- []sparseEntry{}, io.ErrUnexpectedEOF},
|
|
| 613 |
- {t11 + t21 + strings.Repeat("\x00", 512),
|
|
| 614 |
- mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
|
|
| 615 |
- []sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}, {1, 1}, {2, 1}}, nil},
|
|
| 616 |
- } |
|
| 617 |
- |
|
| 618 |
- for i, v := range vectors {
|
|
| 619 |
- tr := Reader{r: strings.NewReader(v.data)}
|
|
| 620 |
- hdr := new(Header) |
|
| 621 |
- got, err := tr.readOldGNUSparseMap(hdr, v.rawHdr) |
|
| 622 |
- if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
|
|
| 623 |
- t.Errorf("test %d, readOldGNUSparseMap(...): got %v, want %v", i, got, v.want)
|
|
| 624 |
- } |
|
| 625 |
- if err != v.err {
|
|
| 626 |
- t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
|
|
| 627 |
- } |
|
| 628 |
- } |
|
| 629 |
-} |
|
| 630 |
- |
|
| 631 |
-func TestReadGNUSparseMap0x1(t *testing.T) {
|
|
| 632 |
- const ( |
|
| 633 |
- maxUint = ^uint(0) |
|
| 634 |
- maxInt = int(maxUint >> 1) |
|
| 635 |
- ) |
|
| 636 |
- var ( |
|
| 637 |
- big1 = fmt.Sprintf("%d", int64(maxInt))
|
|
| 638 |
- big2 = fmt.Sprintf("%d", (int64(maxInt)/2)+1)
|
|
| 639 |
- big3 = fmt.Sprintf("%d", (int64(maxInt) / 3))
|
|
| 640 |
- ) |
|
| 641 |
- |
|
| 642 |
- vectors := []struct {
|
|
| 643 |
- extHdrs map[string]string // Input data |
|
| 644 |
- sparseMap []sparseEntry // Expected sparse entries to be outputted |
|
| 645 |
- err error // Expected errors that may be raised |
|
| 646 |
- }{{
|
|
| 647 |
- extHdrs: map[string]string{paxGNUSparseNumBlocks: "-4"},
|
|
| 648 |
- err: ErrHeader, |
|
| 649 |
- }, {
|
|
| 650 |
- extHdrs: map[string]string{paxGNUSparseNumBlocks: "fee "},
|
|
| 651 |
- err: ErrHeader, |
|
| 652 |
- }, {
|
|
| 653 |
- extHdrs: map[string]string{
|
|
| 654 |
- paxGNUSparseNumBlocks: big1, |
|
| 655 |
- paxGNUSparseMap: "0,5,10,5,20,5,30,5", |
|
| 656 |
- }, |
|
| 657 |
- err: ErrHeader, |
|
| 658 |
- }, {
|
|
| 659 |
- extHdrs: map[string]string{
|
|
| 660 |
- paxGNUSparseNumBlocks: big2, |
|
| 661 |
- paxGNUSparseMap: "0,5,10,5,20,5,30,5", |
|
| 662 |
- }, |
|
| 663 |
- err: ErrHeader, |
|
| 664 |
- }, {
|
|
| 665 |
- extHdrs: map[string]string{
|
|
| 666 |
- paxGNUSparseNumBlocks: big3, |
|
| 667 |
- paxGNUSparseMap: "0,5,10,5,20,5,30,5", |
|
| 668 |
- }, |
|
| 669 |
- err: ErrHeader, |
|
| 670 |
- }, {
|
|
| 671 |
- extHdrs: map[string]string{
|
|
| 672 |
- paxGNUSparseNumBlocks: "4", |
|
| 673 |
- paxGNUSparseMap: "0.5,5,10,5,20,5,30,5", |
|
| 674 |
- }, |
|
| 675 |
- err: ErrHeader, |
|
| 676 |
- }, {
|
|
| 677 |
- extHdrs: map[string]string{
|
|
| 678 |
- paxGNUSparseNumBlocks: "4", |
|
| 679 |
- paxGNUSparseMap: "0,5.5,10,5,20,5,30,5", |
|
| 680 |
- }, |
|
| 681 |
- err: ErrHeader, |
|
| 682 |
- }, {
|
|
| 683 |
- extHdrs: map[string]string{
|
|
| 684 |
- paxGNUSparseNumBlocks: "4", |
|
| 685 |
- paxGNUSparseMap: "0,fewafewa.5,fewafw,5,20,5,30,5", |
|
| 686 |
- }, |
|
| 687 |
- err: ErrHeader, |
|
| 688 |
- }, {
|
|
| 689 |
- extHdrs: map[string]string{
|
|
| 690 |
- paxGNUSparseNumBlocks: "4", |
|
| 691 |
- paxGNUSparseMap: "0,5,10,5,20,5,30,5", |
|
| 692 |
- }, |
|
| 693 |
- sparseMap: []sparseEntry{{0, 5}, {10, 5}, {20, 5}, {30, 5}},
|
|
| 694 |
- }} |
|
| 695 |
- |
|
| 696 |
- for i, v := range vectors {
|
|
| 697 |
- sp, err := readGNUSparseMap0x1(v.extHdrs) |
|
| 698 |
- if !reflect.DeepEqual(sp, v.sparseMap) && !(len(sp) == 0 && len(v.sparseMap) == 0) {
|
|
| 699 |
- t.Errorf("test %d, readGNUSparseMap0x1(...): got %v, want %v", i, sp, v.sparseMap)
|
|
| 700 |
- } |
|
| 701 |
- if err != v.err {
|
|
| 702 |
- t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
|
|
| 703 |
- } |
|
| 704 |
- } |
|
| 705 |
-} |
|
| 706 |
- |
|
| 707 |
-func TestReadGNUSparseMap1x0(t *testing.T) {
|
|
| 708 |
- sp := []sparseEntry{{1, 2}, {3, 4}}
|
|
| 709 |
- for i := 0; i < 98; i++ {
|
|
| 710 |
- sp = append(sp, sparseEntry{54321, 12345})
|
|
| 711 |
- } |
|
| 712 |
- |
|
| 713 |
- vectors := []struct {
|
|
| 714 |
- input string // Input data |
|
| 715 |
- sparseMap []sparseEntry // Expected sparse entries to be outputted |
|
| 716 |
- cnt int // Expected number of bytes read |
|
| 717 |
- err error // Expected errors that may be raised |
|
| 718 |
- }{{
|
|
| 719 |
- input: "", |
|
| 720 |
- cnt: 0, |
|
| 721 |
- err: io.ErrUnexpectedEOF, |
|
| 722 |
- }, {
|
|
| 723 |
- input: "ab", |
|
| 724 |
- cnt: 2, |
|
| 725 |
- err: io.ErrUnexpectedEOF, |
|
| 726 |
- }, {
|
|
| 727 |
- input: strings.Repeat("\x00", 512),
|
|
| 728 |
- cnt: 512, |
|
| 729 |
- err: io.ErrUnexpectedEOF, |
|
| 730 |
- }, {
|
|
| 731 |
- input: strings.Repeat("\x00", 511) + "\n",
|
|
| 732 |
- cnt: 512, |
|
| 733 |
- err: ErrHeader, |
|
| 734 |
- }, {
|
|
| 735 |
- input: strings.Repeat("\n", 512),
|
|
| 736 |
- cnt: 512, |
|
| 737 |
- err: ErrHeader, |
|
| 738 |
- }, {
|
|
| 739 |
- input: "0\n" + strings.Repeat("\x00", 510) + strings.Repeat("a", 512),
|
|
| 740 |
- sparseMap: []sparseEntry{},
|
|
| 741 |
- cnt: 512, |
|
| 742 |
- }, {
|
|
| 743 |
- input: strings.Repeat("0", 512) + "0\n" + strings.Repeat("\x00", 510),
|
|
| 744 |
- sparseMap: []sparseEntry{},
|
|
| 745 |
- cnt: 1024, |
|
| 746 |
- }, {
|
|
| 747 |
- input: strings.Repeat("0", 1024) + "1\n2\n3\n" + strings.Repeat("\x00", 506),
|
|
| 748 |
- sparseMap: []sparseEntry{{2, 3}},
|
|
| 749 |
- cnt: 1536, |
|
| 750 |
- }, {
|
|
| 751 |
- input: strings.Repeat("0", 1024) + "1\n2\n\n" + strings.Repeat("\x00", 509),
|
|
| 752 |
- cnt: 1536, |
|
| 753 |
- err: ErrHeader, |
|
| 754 |
- }, {
|
|
| 755 |
- input: strings.Repeat("0", 1024) + "1\n2\n" + strings.Repeat("\x00", 508),
|
|
| 756 |
- cnt: 1536, |
|
| 757 |
- err: io.ErrUnexpectedEOF, |
|
| 758 |
- }, {
|
|
| 759 |
- input: "-1\n2\n\n" + strings.Repeat("\x00", 506),
|
|
| 760 |
- cnt: 512, |
|
| 761 |
- err: ErrHeader, |
|
| 762 |
- }, {
|
|
| 763 |
- input: "1\nk\n2\n" + strings.Repeat("\x00", 506),
|
|
| 764 |
- cnt: 512, |
|
| 765 |
- err: ErrHeader, |
|
| 766 |
- }, {
|
|
| 767 |
- input: "100\n1\n2\n3\n4\n" + strings.Repeat("54321\n0000000000000012345\n", 98) + strings.Repeat("\x00", 512),
|
|
| 768 |
- cnt: 2560, |
|
| 769 |
- sparseMap: sp, |
|
| 770 |
- }} |
|
| 771 |
- |
|
| 772 |
- for i, v := range vectors {
|
|
| 773 |
- r := strings.NewReader(v.input) |
|
| 774 |
- sp, err := readGNUSparseMap1x0(r) |
|
| 775 |
- if !reflect.DeepEqual(sp, v.sparseMap) && !(len(sp) == 0 && len(v.sparseMap) == 0) {
|
|
| 776 |
- t.Errorf("test %d, readGNUSparseMap1x0(...): got %v, want %v", i, sp, v.sparseMap)
|
|
| 777 |
- } |
|
| 778 |
- if numBytes := len(v.input) - r.Len(); numBytes != v.cnt {
|
|
| 779 |
- t.Errorf("test %d, bytes read: got %v, want %v", i, numBytes, v.cnt)
|
|
| 780 |
- } |
|
| 781 |
- if err != v.err {
|
|
| 782 |
- t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
|
|
| 783 |
- } |
|
| 784 |
- } |
|
| 785 |
-} |
|
| 786 |
- |
|
| 787 |
-func TestUninitializedRead(t *testing.T) {
|
|
| 788 |
- f, err := os.Open("testdata/gnu.tar")
|
|
| 789 |
- if err != nil {
|
|
| 790 |
- t.Fatalf("Unexpected error: %v", err)
|
|
| 791 |
- } |
|
| 792 |
- defer f.Close() |
|
| 793 |
- |
|
| 794 |
- tr := NewReader(f) |
|
| 795 |
- _, err = tr.Read([]byte{})
|
|
| 796 |
- if err == nil || err != io.EOF {
|
|
| 797 |
- t.Errorf("Unexpected error: %v, wanted %v", err, io.EOF)
|
|
| 798 |
- } |
|
| 799 |
- |
|
| 800 |
-} |
|
| 801 |
- |
|
| 802 |
-type reader struct{ io.Reader }
|
|
| 803 |
-type readSeeker struct{ io.ReadSeeker }
|
|
| 804 |
-type readBadSeeker struct{ io.ReadSeeker }
|
|
| 805 |
- |
|
| 806 |
-func (rbs *readBadSeeker) Seek(int64, int) (int64, error) { return 0, fmt.Errorf("illegal seek") }
|
|
| 807 |
- |
|
| 808 |
-// TestReadTruncation test the ending condition on various truncated files and |
|
| 809 |
-// that truncated files are still detected even if the underlying io.Reader |
|
| 810 |
-// satisfies io.Seeker. |
|
| 811 |
-func TestReadTruncation(t *testing.T) {
|
|
| 812 |
- var ss []string |
|
| 813 |
- for _, p := range []string{
|
|
| 814 |
- "testdata/gnu.tar", |
|
| 815 |
- "testdata/ustar-file-reg.tar", |
|
| 816 |
- "testdata/pax-path-hdr.tar", |
|
| 817 |
- "testdata/sparse-formats.tar", |
|
| 818 |
- } {
|
|
| 819 |
- buf, err := ioutil.ReadFile(p) |
|
| 820 |
- if err != nil {
|
|
| 821 |
- t.Fatalf("unexpected error: %v", err)
|
|
| 822 |
- } |
|
| 823 |
- ss = append(ss, string(buf)) |
|
| 824 |
- } |
|
| 825 |
- |
|
| 826 |
- data1, data2, pax, sparse := ss[0], ss[1], ss[2], ss[3] |
|
| 827 |
- data2 += strings.Repeat("\x00", 10*512)
|
|
| 828 |
- trash := strings.Repeat("garbage ", 64) // Exactly 512 bytes
|
|
| 829 |
- |
|
| 830 |
- vectors := []struct {
|
|
| 831 |
- input string // Input stream |
|
| 832 |
- cnt int // Expected number of headers read |
|
| 833 |
- err error // Expected error outcome |
|
| 834 |
- }{
|
|
| 835 |
- {"", 0, io.EOF}, // Empty file is a "valid" tar file
|
|
| 836 |
- {data1[:511], 0, io.ErrUnexpectedEOF},
|
|
| 837 |
- {data1[:512], 1, io.ErrUnexpectedEOF},
|
|
| 838 |
- {data1[:1024], 1, io.EOF},
|
|
| 839 |
- {data1[:1536], 2, io.ErrUnexpectedEOF},
|
|
| 840 |
- {data1[:2048], 2, io.EOF},
|
|
| 841 |
- {data1, 2, io.EOF},
|
|
| 842 |
- {data1[:2048] + data2[:1536], 3, io.EOF},
|
|
| 843 |
- {data2[:511], 0, io.ErrUnexpectedEOF},
|
|
| 844 |
- {data2[:512], 1, io.ErrUnexpectedEOF},
|
|
| 845 |
- {data2[:1195], 1, io.ErrUnexpectedEOF},
|
|
| 846 |
- {data2[:1196], 1, io.EOF}, // Exact end of data and start of padding
|
|
| 847 |
- {data2[:1200], 1, io.EOF},
|
|
| 848 |
- {data2[:1535], 1, io.EOF},
|
|
| 849 |
- {data2[:1536], 1, io.EOF}, // Exact end of padding
|
|
| 850 |
- {data2[:1536] + trash[:1], 1, io.ErrUnexpectedEOF},
|
|
| 851 |
- {data2[:1536] + trash[:511], 1, io.ErrUnexpectedEOF},
|
|
| 852 |
- {data2[:1536] + trash, 1, ErrHeader},
|
|
| 853 |
- {data2[:2048], 1, io.EOF}, // Exactly 1 empty block
|
|
| 854 |
- {data2[:2048] + trash[:1], 1, io.ErrUnexpectedEOF},
|
|
| 855 |
- {data2[:2048] + trash[:511], 1, io.ErrUnexpectedEOF},
|
|
| 856 |
- {data2[:2048] + trash, 1, ErrHeader},
|
|
| 857 |
- {data2[:2560], 1, io.EOF}, // Exactly 2 empty blocks (normal end-of-stream)
|
|
| 858 |
- {data2[:2560] + trash[:1], 1, io.EOF},
|
|
| 859 |
- {data2[:2560] + trash[:511], 1, io.EOF},
|
|
| 860 |
- {data2[:2560] + trash, 1, io.EOF},
|
|
| 861 |
- {data2[:3072], 1, io.EOF},
|
|
| 862 |
- {pax, 0, io.EOF}, // PAX header without data is a "valid" tar file
|
|
| 863 |
- {pax + trash[:1], 0, io.ErrUnexpectedEOF},
|
|
| 864 |
- {pax + trash[:511], 0, io.ErrUnexpectedEOF},
|
|
| 865 |
- {sparse[:511], 0, io.ErrUnexpectedEOF},
|
|
| 866 |
- {sparse[:512], 0, io.ErrUnexpectedEOF},
|
|
| 867 |
- {sparse[:3584], 1, io.EOF},
|
|
| 868 |
- {sparse[:9200], 1, io.EOF}, // Terminate in padding of sparse header
|
|
| 869 |
- {sparse[:9216], 1, io.EOF},
|
|
| 870 |
- {sparse[:9728], 2, io.ErrUnexpectedEOF},
|
|
| 871 |
- {sparse[:10240], 2, io.EOF},
|
|
| 872 |
- {sparse[:11264], 2, io.ErrUnexpectedEOF},
|
|
| 873 |
- {sparse, 5, io.EOF},
|
|
| 874 |
- {sparse + trash, 5, io.EOF},
|
|
| 875 |
- } |
|
| 876 |
- |
|
| 877 |
- for i, v := range vectors {
|
|
| 878 |
- for j := 0; j < 6; j++ {
|
|
| 879 |
- var tr *Reader |
|
| 880 |
- var s1, s2 string |
|
| 881 |
- |
|
| 882 |
- switch j {
|
|
| 883 |
- case 0: |
|
| 884 |
- tr = NewReader(&reader{strings.NewReader(v.input)})
|
|
| 885 |
- s1, s2 = "io.Reader", "auto" |
|
| 886 |
- case 1: |
|
| 887 |
- tr = NewReader(&reader{strings.NewReader(v.input)})
|
|
| 888 |
- s1, s2 = "io.Reader", "manual" |
|
| 889 |
- case 2: |
|
| 890 |
- tr = NewReader(&readSeeker{strings.NewReader(v.input)})
|
|
| 891 |
- s1, s2 = "io.ReadSeeker", "auto" |
|
| 892 |
- case 3: |
|
| 893 |
- tr = NewReader(&readSeeker{strings.NewReader(v.input)})
|
|
| 894 |
- s1, s2 = "io.ReadSeeker", "manual" |
|
| 895 |
- case 4: |
|
| 896 |
- tr = NewReader(&readBadSeeker{strings.NewReader(v.input)})
|
|
| 897 |
- s1, s2 = "ReadBadSeeker", "auto" |
|
| 898 |
- case 5: |
|
| 899 |
- tr = NewReader(&readBadSeeker{strings.NewReader(v.input)})
|
|
| 900 |
- s1, s2 = "ReadBadSeeker", "manual" |
|
| 901 |
- } |
|
| 902 |
- |
|
| 903 |
- var cnt int |
|
| 904 |
- var err error |
|
| 905 |
- for {
|
|
| 906 |
- if _, err = tr.Next(); err != nil {
|
|
| 907 |
- break |
|
| 908 |
- } |
|
| 909 |
- cnt++ |
|
| 910 |
- if s2 == "manual" {
|
|
| 911 |
- if _, err = io.Copy(ioutil.Discard, tr); err != nil {
|
|
| 912 |
- break |
|
| 913 |
- } |
|
| 914 |
- } |
|
| 915 |
- } |
|
| 916 |
- if err != v.err {
|
|
| 917 |
- t.Errorf("test %d, NewReader(%s(...)) with %s discard: got %v, want %v",
|
|
| 918 |
- i, s1, s2, err, v.err) |
|
| 919 |
- } |
|
| 920 |
- if cnt != v.cnt {
|
|
| 921 |
- t.Errorf("test %d, NewReader(%s(...)) with %s discard: got %d headers, want %d headers",
|
|
| 922 |
- i, s1, s2, cnt, v.cnt) |
|
| 923 |
- } |
|
| 924 |
- } |
|
| 925 |
- } |
|
| 926 |
-} |
|
| 927 |
- |
|
| 928 |
-// TestReadHeaderOnly tests that Reader does not attempt to read special |
|
| 929 |
-// header-only files. |
|
| 930 |
-func TestReadHeaderOnly(t *testing.T) {
|
|
| 931 |
- f, err := os.Open("testdata/hdr-only.tar")
|
|
| 932 |
- if err != nil {
|
|
| 933 |
- t.Fatalf("unexpected error: %v", err)
|
|
| 934 |
- } |
|
| 935 |
- defer f.Close() |
|
| 936 |
- |
|
| 937 |
- var hdrs []*Header |
|
| 938 |
- tr := NewReader(f) |
|
| 939 |
- for {
|
|
| 940 |
- hdr, err := tr.Next() |
|
| 941 |
- if err == io.EOF {
|
|
| 942 |
- break |
|
| 943 |
- } |
|
| 944 |
- if err != nil {
|
|
| 945 |
- t.Errorf("Next(): got %v, want %v", err, nil)
|
|
| 946 |
- continue |
|
| 947 |
- } |
|
| 948 |
- hdrs = append(hdrs, hdr) |
|
| 949 |
- |
|
| 950 |
- // If a special flag, we should read nothing. |
|
| 951 |
- cnt, _ := io.ReadFull(tr, []byte{0})
|
|
| 952 |
- if cnt > 0 && hdr.Typeflag != TypeReg {
|
|
| 953 |
- t.Errorf("ReadFull(...): got %d bytes, want 0 bytes", cnt)
|
|
| 954 |
- } |
|
| 955 |
- } |
|
| 956 |
- |
|
| 957 |
- // File is crafted with 16 entries. The later 8 are identical to the first |
|
| 958 |
- // 8 except that the size is set. |
|
| 959 |
- if len(hdrs) != 16 {
|
|
| 960 |
- t.Fatalf("len(hdrs): got %d, want %d", len(hdrs), 16)
|
|
| 961 |
- } |
|
| 962 |
- for i := 0; i < 8; i++ {
|
|
| 963 |
- hdr1, hdr2 := hdrs[i+0], hdrs[i+8] |
|
| 964 |
- hdr1.Size, hdr2.Size = 0, 0 |
|
| 965 |
- if !reflect.DeepEqual(*hdr1, *hdr2) {
|
|
| 966 |
- t.Errorf("incorrect header:\ngot %+v\nwant %+v", *hdr1, *hdr2)
|
|
| 967 |
- } |
|
| 968 |
- } |
|
| 969 |
-} |
|
| 970 |
- |
|
| 971 |
-func TestMergePAX(t *testing.T) {
|
|
| 972 |
- vectors := []struct {
|
|
| 973 |
- in map[string]string |
|
| 974 |
- want *Header |
|
| 975 |
- ok bool |
|
| 976 |
- }{{
|
|
| 977 |
- in: map[string]string{
|
|
| 978 |
- "path": "a/b/c", |
|
| 979 |
- "uid": "1000", |
|
| 980 |
- "mtime": "1350244992.023960108", |
|
| 981 |
- }, |
|
| 982 |
- want: &Header{
|
|
| 983 |
- Name: "a/b/c", |
|
| 984 |
- Uid: 1000, |
|
| 985 |
- ModTime: time.Unix(1350244992, 23960108), |
|
| 986 |
- }, |
|
| 987 |
- ok: true, |
|
| 988 |
- }, {
|
|
| 989 |
- in: map[string]string{
|
|
| 990 |
- "gid": "gtgergergersagersgers", |
|
| 991 |
- }, |
|
| 992 |
- }, {
|
|
| 993 |
- in: map[string]string{
|
|
| 994 |
- "missing": "missing", |
|
| 995 |
- "SCHILY.xattr.key": "value", |
|
| 996 |
- }, |
|
| 997 |
- want: &Header{
|
|
| 998 |
- Xattrs: map[string]string{"key": "value"},
|
|
| 999 |
- }, |
|
| 1000 |
- ok: true, |
|
| 1001 |
- }} |
|
| 1002 |
- |
|
| 1003 |
- for i, v := range vectors {
|
|
| 1004 |
- got := new(Header) |
|
| 1005 |
- err := mergePAX(got, v.in) |
|
| 1006 |
- if v.ok && !reflect.DeepEqual(*got, *v.want) {
|
|
| 1007 |
- t.Errorf("test %d, mergePAX(...):\ngot %+v\nwant %+v", i, *got, *v.want)
|
|
| 1008 |
- } |
|
| 1009 |
- if ok := err == nil; ok != v.ok {
|
|
| 1010 |
- t.Errorf("test %d, mergePAX(...): got %v, want %v", i, ok, v.ok)
|
|
| 1011 |
- } |
|
| 1012 |
- } |
|
| 1013 |
-} |
|
| 1014 |
- |
|
| 1015 |
-func TestParsePAX(t *testing.T) {
|
|
| 1016 |
- vectors := []struct {
|
|
| 1017 |
- in string |
|
| 1018 |
- want map[string]string |
|
| 1019 |
- ok bool |
|
| 1020 |
- }{
|
|
| 1021 |
- {"", nil, true},
|
|
| 1022 |
- {"6 k=1\n", map[string]string{"k": "1"}, true},
|
|
| 1023 |
- {"10 a=name\n", map[string]string{"a": "name"}, true},
|
|
| 1024 |
- {"9 a=name\n", map[string]string{"a": "name"}, true},
|
|
| 1025 |
- {"30 mtime=1350244992.023960108\n", map[string]string{"mtime": "1350244992.023960108"}, true},
|
|
| 1026 |
- {"3 somelongkey=\n", nil, false},
|
|
| 1027 |
- {"50 tooshort=\n", nil, false},
|
|
| 1028 |
- {"13 key1=haha\n13 key2=nana\n13 key3=kaka\n",
|
|
| 1029 |
- map[string]string{"key1": "haha", "key2": "nana", "key3": "kaka"}, true},
|
|
| 1030 |
- {"13 key1=val1\n13 key2=val2\n8 key1=\n",
|
|
| 1031 |
- map[string]string{"key2": "val2"}, true},
|
|
| 1032 |
- {"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=2\n" +
|
|
| 1033 |
- "23 GNU.sparse.offset=1\n25 GNU.sparse.numbytes=2\n" + |
|
| 1034 |
- "23 GNU.sparse.offset=3\n25 GNU.sparse.numbytes=4\n", |
|
| 1035 |
- map[string]string{paxGNUSparseSize: "10", paxGNUSparseNumBlocks: "2", paxGNUSparseMap: "1,2,3,4"}, true},
|
|
| 1036 |
- {"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=1\n" +
|
|
| 1037 |
- "25 GNU.sparse.numbytes=2\n23 GNU.sparse.offset=1\n", |
|
| 1038 |
- nil, false}, |
|
| 1039 |
- {"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=1\n" +
|
|
| 1040 |
- "25 GNU.sparse.offset=1,2\n25 GNU.sparse.numbytes=2\n", |
|
| 1041 |
- nil, false}, |
|
| 1042 |
- } |
|
| 1043 |
- |
|
| 1044 |
- for i, v := range vectors {
|
|
| 1045 |
- r := strings.NewReader(v.in) |
|
| 1046 |
- got, err := parsePAX(r) |
|
| 1047 |
- if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
|
|
| 1048 |
- t.Errorf("test %d, parsePAX(...):\ngot %v\nwant %v", i, got, v.want)
|
|
| 1049 |
- } |
|
| 1050 |
- if ok := err == nil; ok != v.ok {
|
|
| 1051 |
- t.Errorf("test %d, parsePAX(...): got %v, want %v", i, ok, v.ok)
|
|
| 1052 |
- } |
|
| 1053 |
- } |
|
| 1054 |
-} |
| 1055 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,319 +0,0 @@ |
| 1 |
-// Copyright 2016 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 |
- "math" |
|
| 9 |
- "strings" |
|
| 10 |
- "testing" |
|
| 11 |
- "time" |
|
| 12 |
-) |
|
| 13 |
- |
|
| 14 |
-func TestFitsInBase256(t *testing.T) {
|
|
| 15 |
- vectors := []struct {
|
|
| 16 |
- in int64 |
|
| 17 |
- width int |
|
| 18 |
- ok bool |
|
| 19 |
- }{
|
|
| 20 |
- {+1, 8, true},
|
|
| 21 |
- {0, 8, true},
|
|
| 22 |
- {-1, 8, true},
|
|
| 23 |
- {1 << 56, 8, false},
|
|
| 24 |
- {(1 << 56) - 1, 8, true},
|
|
| 25 |
- {-1 << 56, 8, true},
|
|
| 26 |
- {(-1 << 56) - 1, 8, false},
|
|
| 27 |
- {121654, 8, true},
|
|
| 28 |
- {-9849849, 8, true},
|
|
| 29 |
- {math.MaxInt64, 9, true},
|
|
| 30 |
- {0, 9, true},
|
|
| 31 |
- {math.MinInt64, 9, true},
|
|
| 32 |
- {math.MaxInt64, 12, true},
|
|
| 33 |
- {0, 12, true},
|
|
| 34 |
- {math.MinInt64, 12, true},
|
|
| 35 |
- } |
|
| 36 |
- |
|
| 37 |
- for _, v := range vectors {
|
|
| 38 |
- ok := fitsInBase256(v.width, v.in) |
|
| 39 |
- if ok != v.ok {
|
|
| 40 |
- t.Errorf("fitsInBase256(%d, %d): got %v, want %v", v.in, v.width, ok, v.ok)
|
|
| 41 |
- } |
|
| 42 |
- } |
|
| 43 |
-} |
|
| 44 |
- |
|
| 45 |
-func TestParseNumeric(t *testing.T) {
|
|
| 46 |
- vectors := []struct {
|
|
| 47 |
- in string |
|
| 48 |
- want int64 |
|
| 49 |
- ok bool |
|
| 50 |
- }{
|
|
| 51 |
- // Test base-256 (binary) encoded values. |
|
| 52 |
- {"", 0, true},
|
|
| 53 |
- {"\x80", 0, true},
|
|
| 54 |
- {"\x80\x00", 0, true},
|
|
| 55 |
- {"\x80\x00\x00", 0, true},
|
|
| 56 |
- {"\xbf", (1 << 6) - 1, true},
|
|
| 57 |
- {"\xbf\xff", (1 << 14) - 1, true},
|
|
| 58 |
- {"\xbf\xff\xff", (1 << 22) - 1, true},
|
|
| 59 |
- {"\xff", -1, true},
|
|
| 60 |
- {"\xff\xff", -1, true},
|
|
| 61 |
- {"\xff\xff\xff", -1, true},
|
|
| 62 |
- {"\xc0", -1 * (1 << 6), true},
|
|
| 63 |
- {"\xc0\x00", -1 * (1 << 14), true},
|
|
| 64 |
- {"\xc0\x00\x00", -1 * (1 << 22), true},
|
|
| 65 |
- {"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
|
|
| 66 |
- {"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
|
|
| 67 |
- {"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
|
|
| 68 |
- {"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
|
|
| 69 |
- {"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
|
|
| 70 |
- {"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
|
|
| 71 |
- {"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
|
|
| 72 |
- {"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
|
|
| 73 |
- {"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
|
|
| 74 |
- |
|
| 75 |
- // Test base-8 (octal) encoded values. |
|
| 76 |
- {"0000000\x00", 0, true},
|
|
| 77 |
- {" \x0000000\x00", 0, true},
|
|
| 78 |
- {" \x0000003\x00", 3, true},
|
|
| 79 |
- {"00000000227\x00", 0227, true},
|
|
| 80 |
- {"032033\x00 ", 032033, true},
|
|
| 81 |
- {"320330\x00 ", 0320330, true},
|
|
| 82 |
- {"0000660\x00 ", 0660, true},
|
|
| 83 |
- {"\x00 0000660\x00 ", 0660, true},
|
|
| 84 |
- {"0123456789abcdef", 0, false},
|
|
| 85 |
- {"0123456789\x00abcdef", 0, false},
|
|
| 86 |
- {"01234567\x0089abcdef", 342391, true},
|
|
| 87 |
- {"0123\x7e\x5f\x264123", 0, false},
|
|
| 88 |
- } |
|
| 89 |
- |
|
| 90 |
- for _, v := range vectors {
|
|
| 91 |
- var p parser |
|
| 92 |
- got := p.parseNumeric([]byte(v.in)) |
|
| 93 |
- ok := (p.err == nil) |
|
| 94 |
- if ok != v.ok {
|
|
| 95 |
- if v.ok {
|
|
| 96 |
- t.Errorf("parseNumeric(%q): got parsing failure, want success", v.in)
|
|
| 97 |
- } else {
|
|
| 98 |
- t.Errorf("parseNumeric(%q): got parsing success, want failure", v.in)
|
|
| 99 |
- } |
|
| 100 |
- } |
|
| 101 |
- if ok && got != v.want {
|
|
| 102 |
- t.Errorf("parseNumeric(%q): got %d, want %d", v.in, got, v.want)
|
|
| 103 |
- } |
|
| 104 |
- } |
|
| 105 |
-} |
|
| 106 |
- |
|
| 107 |
-func TestFormatNumeric(t *testing.T) {
|
|
| 108 |
- vectors := []struct {
|
|
| 109 |
- in int64 |
|
| 110 |
- want string |
|
| 111 |
- ok bool |
|
| 112 |
- }{
|
|
| 113 |
- // Test base-256 (binary) encoded values. |
|
| 114 |
- {-1, "\xff", true},
|
|
| 115 |
- {-1, "\xff\xff", true},
|
|
| 116 |
- {-1, "\xff\xff\xff", true},
|
|
| 117 |
- {(1 << 0), "0", false},
|
|
| 118 |
- {(1 << 8) - 1, "\x80\xff", true},
|
|
| 119 |
- {(1 << 8), "0\x00", false},
|
|
| 120 |
- {(1 << 16) - 1, "\x80\xff\xff", true},
|
|
| 121 |
- {(1 << 16), "00\x00", false},
|
|
| 122 |
- {-1 * (1 << 0), "\xff", true},
|
|
| 123 |
- {-1*(1<<0) - 1, "0", false},
|
|
| 124 |
- {-1 * (1 << 8), "\xff\x00", true},
|
|
| 125 |
- {-1*(1<<8) - 1, "0\x00", false},
|
|
| 126 |
- {-1 * (1 << 16), "\xff\x00\x00", true},
|
|
| 127 |
- {-1*(1<<16) - 1, "00\x00", false},
|
|
| 128 |
- {537795476381659745, "0000000\x00", false},
|
|
| 129 |
- {537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
|
|
| 130 |
- {-615126028225187231, "0000000\x00", false},
|
|
| 131 |
- {-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
|
|
| 132 |
- {math.MaxInt64, "0000000\x00", false},
|
|
| 133 |
- {math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
|
|
| 134 |
- {math.MinInt64, "0000000\x00", false},
|
|
| 135 |
- {math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
|
|
| 136 |
- {math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
|
|
| 137 |
- {math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
|
|
| 138 |
- } |
|
| 139 |
- |
|
| 140 |
- for _, v := range vectors {
|
|
| 141 |
- var f formatter |
|
| 142 |
- got := make([]byte, len(v.want)) |
|
| 143 |
- f.formatNumeric(got, v.in) |
|
| 144 |
- ok := (f.err == nil) |
|
| 145 |
- if ok != v.ok {
|
|
| 146 |
- if v.ok {
|
|
| 147 |
- t.Errorf("formatNumeric(%d): got formatting failure, want success", v.in)
|
|
| 148 |
- } else {
|
|
| 149 |
- t.Errorf("formatNumeric(%d): got formatting success, want failure", v.in)
|
|
| 150 |
- } |
|
| 151 |
- } |
|
| 152 |
- if string(got) != v.want {
|
|
| 153 |
- t.Errorf("formatNumeric(%d): got %q, want %q", v.in, got, v.want)
|
|
| 154 |
- } |
|
| 155 |
- } |
|
| 156 |
-} |
|
| 157 |
- |
|
| 158 |
-func TestParsePAXTime(t *testing.T) {
|
|
| 159 |
- vectors := []struct {
|
|
| 160 |
- in string |
|
| 161 |
- want time.Time |
|
| 162 |
- ok bool |
|
| 163 |
- }{
|
|
| 164 |
- {"1350244992.023960108", time.Unix(1350244992, 23960108), true},
|
|
| 165 |
- {"1350244992.02396010", time.Unix(1350244992, 23960100), true},
|
|
| 166 |
- {"1350244992.0239601089", time.Unix(1350244992, 23960108), true},
|
|
| 167 |
- {"1350244992.3", time.Unix(1350244992, 300000000), true},
|
|
| 168 |
- {"1350244992", time.Unix(1350244992, 0), true},
|
|
| 169 |
- {"-1.000000001", time.Unix(-1, -1e0+0e0), true},
|
|
| 170 |
- {"-1.000001", time.Unix(-1, -1e3+0e0), true},
|
|
| 171 |
- {"-1.001000", time.Unix(-1, -1e6+0e0), true},
|
|
| 172 |
- {"-1", time.Unix(-1, -0e0+0e0), true},
|
|
| 173 |
- {"-1.999000", time.Unix(-1, -1e9+1e6), true},
|
|
| 174 |
- {"-1.999999", time.Unix(-1, -1e9+1e3), true},
|
|
| 175 |
- {"-1.999999999", time.Unix(-1, -1e9+1e0), true},
|
|
| 176 |
- {"0.000000001", time.Unix(0, 1e0+0e0), true},
|
|
| 177 |
- {"0.000001", time.Unix(0, 1e3+0e0), true},
|
|
| 178 |
- {"0.001000", time.Unix(0, 1e6+0e0), true},
|
|
| 179 |
- {"0", time.Unix(0, 0e0), true},
|
|
| 180 |
- {"0.999000", time.Unix(0, 1e9-1e6), true},
|
|
| 181 |
- {"0.999999", time.Unix(0, 1e9-1e3), true},
|
|
| 182 |
- {"0.999999999", time.Unix(0, 1e9-1e0), true},
|
|
| 183 |
- {"1.000000001", time.Unix(+1, +1e0-0e0), true},
|
|
| 184 |
- {"1.000001", time.Unix(+1, +1e3-0e0), true},
|
|
| 185 |
- {"1.001000", time.Unix(+1, +1e6-0e0), true},
|
|
| 186 |
- {"1", time.Unix(+1, +0e0-0e0), true},
|
|
| 187 |
- {"1.999000", time.Unix(+1, +1e9-1e6), true},
|
|
| 188 |
- {"1.999999", time.Unix(+1, +1e9-1e3), true},
|
|
| 189 |
- {"1.999999999", time.Unix(+1, +1e9-1e0), true},
|
|
| 190 |
- {"-1350244992.023960108", time.Unix(-1350244992, -23960108), true},
|
|
| 191 |
- {"-1350244992.02396010", time.Unix(-1350244992, -23960100), true},
|
|
| 192 |
- {"-1350244992.0239601089", time.Unix(-1350244992, -23960108), true},
|
|
| 193 |
- {"-1350244992.3", time.Unix(-1350244992, -300000000), true},
|
|
| 194 |
- {"-1350244992", time.Unix(-1350244992, 0), true},
|
|
| 195 |
- {"", time.Time{}, false},
|
|
| 196 |
- {"0", time.Unix(0, 0), true},
|
|
| 197 |
- {"1.", time.Unix(1, 0), true},
|
|
| 198 |
- {"0.0", time.Unix(0, 0), true},
|
|
| 199 |
- {".5", time.Time{}, false},
|
|
| 200 |
- {"-1.3", time.Unix(-1, -3e8), true},
|
|
| 201 |
- {"-1.0", time.Unix(-1, -0e0), true},
|
|
| 202 |
- {"-0.0", time.Unix(-0, -0e0), true},
|
|
| 203 |
- {"-0.1", time.Unix(-0, -1e8), true},
|
|
| 204 |
- {"-0.01", time.Unix(-0, -1e7), true},
|
|
| 205 |
- {"-0.99", time.Unix(-0, -99e7), true},
|
|
| 206 |
- {"-0.98", time.Unix(-0, -98e7), true},
|
|
| 207 |
- {"-1.1", time.Unix(-1, -1e8), true},
|
|
| 208 |
- {"-1.01", time.Unix(-1, -1e7), true},
|
|
| 209 |
- {"-2.99", time.Unix(-2, -99e7), true},
|
|
| 210 |
- {"-5.98", time.Unix(-5, -98e7), true},
|
|
| 211 |
- {"-", time.Time{}, false},
|
|
| 212 |
- {"+", time.Time{}, false},
|
|
| 213 |
- {"-1.-1", time.Time{}, false},
|
|
| 214 |
- {"99999999999999999999999999999999999999999999999", time.Time{}, false},
|
|
| 215 |
- {"0.123456789abcdef", time.Time{}, false},
|
|
| 216 |
- {"foo", time.Time{}, false},
|
|
| 217 |
- {"\x00", time.Time{}, false},
|
|
| 218 |
- {"𝟵𝟴𝟳𝟲𝟱.𝟰𝟯𝟮𝟭𝟬", time.Time{}, false}, // Unicode numbers (U+1D7EC to U+1D7F5)
|
|
| 219 |
- {"98765﹒43210", time.Time{}, false}, // Unicode period (U+FE52)
|
|
| 220 |
- } |
|
| 221 |
- |
|
| 222 |
- for _, v := range vectors {
|
|
| 223 |
- ts, err := parsePAXTime(v.in) |
|
| 224 |
- ok := (err == nil) |
|
| 225 |
- if v.ok != ok {
|
|
| 226 |
- if v.ok {
|
|
| 227 |
- t.Errorf("parsePAXTime(%q): got parsing failure, want success", v.in)
|
|
| 228 |
- } else {
|
|
| 229 |
- t.Errorf("parsePAXTime(%q): got parsing success, want failure", v.in)
|
|
| 230 |
- } |
|
| 231 |
- } |
|
| 232 |
- if ok && !ts.Equal(v.want) {
|
|
| 233 |
- t.Errorf("parsePAXTime(%q): got (%ds %dns), want (%ds %dns)",
|
|
| 234 |
- v.in, ts.Unix(), ts.Nanosecond(), v.want.Unix(), v.want.Nanosecond()) |
|
| 235 |
- } |
|
| 236 |
- } |
|
| 237 |
-} |
|
| 238 |
- |
|
| 239 |
-func TestParsePAXRecord(t *testing.T) {
|
|
| 240 |
- medName := strings.Repeat("CD", 50)
|
|
| 241 |
- longName := strings.Repeat("AB", 100)
|
|
| 242 |
- |
|
| 243 |
- vectors := []struct {
|
|
| 244 |
- in string |
|
| 245 |
- wantRes string |
|
| 246 |
- wantKey string |
|
| 247 |
- wantVal string |
|
| 248 |
- ok bool |
|
| 249 |
- }{
|
|
| 250 |
- {"6 k=v\n\n", "\n", "k", "v", true},
|
|
| 251 |
- {"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
|
|
| 252 |
- {"210 path=" + longName + "\nabc", "abc", "path", longName, true},
|
|
| 253 |
- {"110 path=" + medName + "\n", "", "path", medName, true},
|
|
| 254 |
- {"9 foo=ba\n", "", "foo", "ba", true},
|
|
| 255 |
- {"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
|
|
| 256 |
- {"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true},
|
|
| 257 |
- {"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true},
|
|
| 258 |
- {"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true},
|
|
| 259 |
- {"17 \x00hello=\x00world\n", "", "\x00hello", "\x00world", true},
|
|
| 260 |
- {"1 k=1\n", "1 k=1\n", "", "", false},
|
|
| 261 |
- {"6 k~1\n", "6 k~1\n", "", "", false},
|
|
| 262 |
- {"6_k=1\n", "6_k=1\n", "", "", false},
|
|
| 263 |
- {"6 k=1 ", "6 k=1 ", "", "", false},
|
|
| 264 |
- {"632 k=1\n", "632 k=1\n", "", "", false},
|
|
| 265 |
- {"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
|
|
| 266 |
- {"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
|
|
| 267 |
- {"50 tooshort=\n", "50 tooshort=\n", "", "", false},
|
|
| 268 |
- } |
|
| 269 |
- |
|
| 270 |
- for _, v := range vectors {
|
|
| 271 |
- key, val, res, err := parsePAXRecord(v.in) |
|
| 272 |
- ok := (err == nil) |
|
| 273 |
- if ok != v.ok {
|
|
| 274 |
- if v.ok {
|
|
| 275 |
- t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.in)
|
|
| 276 |
- } else {
|
|
| 277 |
- t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.in)
|
|
| 278 |
- } |
|
| 279 |
- } |
|
| 280 |
- if v.ok && (key != v.wantKey || val != v.wantVal) {
|
|
| 281 |
- t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
|
|
| 282 |
- v.in, key, val, v.wantKey, v.wantVal) |
|
| 283 |
- } |
|
| 284 |
- if res != v.wantRes {
|
|
| 285 |
- t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
|
|
| 286 |
- v.in, res, v.wantRes) |
|
| 287 |
- } |
|
| 288 |
- } |
|
| 289 |
-} |
|
| 290 |
- |
|
| 291 |
-func TestFormatPAXRecord(t *testing.T) {
|
|
| 292 |
- medName := strings.Repeat("CD", 50)
|
|
| 293 |
- longName := strings.Repeat("AB", 100)
|
|
| 294 |
- |
|
| 295 |
- vectors := []struct {
|
|
| 296 |
- inKey string |
|
| 297 |
- inVal string |
|
| 298 |
- want string |
|
| 299 |
- }{
|
|
| 300 |
- {"k", "v", "6 k=v\n"},
|
|
| 301 |
- {"path", "/etc/hosts", "19 path=/etc/hosts\n"},
|
|
| 302 |
- {"path", longName, "210 path=" + longName + "\n"},
|
|
| 303 |
- {"path", medName, "110 path=" + medName + "\n"},
|
|
| 304 |
- {"foo", "ba", "9 foo=ba\n"},
|
|
| 305 |
- {"foo", "bar", "11 foo=bar\n"},
|
|
| 306 |
- {"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n"},
|
|
| 307 |
- {"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n"},
|
|
| 308 |
- {"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n"},
|
|
| 309 |
- {"\x00hello", "\x00world", "17 \x00hello=\x00world\n"},
|
|
| 310 |
- } |
|
| 311 |
- |
|
| 312 |
- for _, v := range vectors {
|
|
| 313 |
- got := formatPAXRecord(v.inKey, v.inVal) |
|
| 314 |
- if got != v.want {
|
|
| 315 |
- t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
|
|
| 316 |
- v.inKey, v.inVal, got, v.want) |
|
| 317 |
- } |
|
| 318 |
- } |
|
| 319 |
-} |
| 320 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,313 +0,0 @@ |
| 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 |
- ModTime: time.Now(), |
|
| 101 |
- } |
|
| 102 |
- // tar only supports second precision. |
|
| 103 |
- hdr.ModTime = hdr.ModTime.Add(-time.Duration(hdr.ModTime.Nanosecond()) * time.Nanosecond) |
|
| 104 |
- if err := tw.WriteHeader(hdr); err != nil {
|
|
| 105 |
- t.Fatalf("tw.WriteHeader: %v", err)
|
|
| 106 |
- } |
|
| 107 |
- if _, err := tw.Write(data); err != nil {
|
|
| 108 |
- t.Fatalf("tw.Write: %v", err)
|
|
| 109 |
- } |
|
| 110 |
- if err := tw.Close(); err != nil {
|
|
| 111 |
- t.Fatalf("tw.Close: %v", err)
|
|
| 112 |
- } |
|
| 113 |
- |
|
| 114 |
- // Read it back. |
|
| 115 |
- tr := NewReader(&b) |
|
| 116 |
- rHdr, err := tr.Next() |
|
| 117 |
- if err != nil {
|
|
| 118 |
- t.Fatalf("tr.Next: %v", err)
|
|
| 119 |
- } |
|
| 120 |
- if !reflect.DeepEqual(rHdr, hdr) {
|
|
| 121 |
- t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr)
|
|
| 122 |
- } |
|
| 123 |
- rData, err := ioutil.ReadAll(tr) |
|
| 124 |
- if err != nil {
|
|
| 125 |
- t.Fatalf("Read: %v", err)
|
|
| 126 |
- } |
|
| 127 |
- if !bytes.Equal(rData, data) {
|
|
| 128 |
- t.Errorf("Data mismatch.\n got %q\nwant %q", rData, data)
|
|
| 129 |
- } |
|
| 130 |
-} |
|
| 131 |
- |
|
| 132 |
-type headerRoundTripTest struct {
|
|
| 133 |
- h *Header |
|
| 134 |
- fm os.FileMode |
|
| 135 |
-} |
|
| 136 |
- |
|
| 137 |
-func TestHeaderRoundTrip(t *testing.T) {
|
|
| 138 |
- vectors := []headerRoundTripTest{{
|
|
| 139 |
- // regular file. |
|
| 140 |
- h: &Header{
|
|
| 141 |
- Name: "test.txt", |
|
| 142 |
- Mode: 0644 | c_ISREG, |
|
| 143 |
- Size: 12, |
|
| 144 |
- ModTime: time.Unix(1360600916, 0), |
|
| 145 |
- Typeflag: TypeReg, |
|
| 146 |
- }, |
|
| 147 |
- fm: 0644, |
|
| 148 |
- }, {
|
|
| 149 |
- // symbolic link. |
|
| 150 |
- h: &Header{
|
|
| 151 |
- Name: "link.txt", |
|
| 152 |
- Mode: 0777 | c_ISLNK, |
|
| 153 |
- Size: 0, |
|
| 154 |
- ModTime: time.Unix(1360600852, 0), |
|
| 155 |
- Typeflag: TypeSymlink, |
|
| 156 |
- }, |
|
| 157 |
- fm: 0777 | os.ModeSymlink, |
|
| 158 |
- }, {
|
|
| 159 |
- // character device node. |
|
| 160 |
- h: &Header{
|
|
| 161 |
- Name: "dev/null", |
|
| 162 |
- Mode: 0666 | c_ISCHR, |
|
| 163 |
- Size: 0, |
|
| 164 |
- ModTime: time.Unix(1360578951, 0), |
|
| 165 |
- Typeflag: TypeChar, |
|
| 166 |
- }, |
|
| 167 |
- fm: 0666 | os.ModeDevice | os.ModeCharDevice, |
|
| 168 |
- }, {
|
|
| 169 |
- // block device node. |
|
| 170 |
- h: &Header{
|
|
| 171 |
- Name: "dev/sda", |
|
| 172 |
- Mode: 0660 | c_ISBLK, |
|
| 173 |
- Size: 0, |
|
| 174 |
- ModTime: time.Unix(1360578954, 0), |
|
| 175 |
- Typeflag: TypeBlock, |
|
| 176 |
- }, |
|
| 177 |
- fm: 0660 | os.ModeDevice, |
|
| 178 |
- }, {
|
|
| 179 |
- // directory. |
|
| 180 |
- h: &Header{
|
|
| 181 |
- Name: "dir/", |
|
| 182 |
- Mode: 0755 | c_ISDIR, |
|
| 183 |
- Size: 0, |
|
| 184 |
- ModTime: time.Unix(1360601116, 0), |
|
| 185 |
- Typeflag: TypeDir, |
|
| 186 |
- }, |
|
| 187 |
- fm: 0755 | os.ModeDir, |
|
| 188 |
- }, {
|
|
| 189 |
- // fifo node. |
|
| 190 |
- h: &Header{
|
|
| 191 |
- Name: "dev/initctl", |
|
| 192 |
- Mode: 0600 | c_ISFIFO, |
|
| 193 |
- Size: 0, |
|
| 194 |
- ModTime: time.Unix(1360578949, 0), |
|
| 195 |
- Typeflag: TypeFifo, |
|
| 196 |
- }, |
|
| 197 |
- fm: 0600 | os.ModeNamedPipe, |
|
| 198 |
- }, {
|
|
| 199 |
- // setuid. |
|
| 200 |
- h: &Header{
|
|
| 201 |
- Name: "bin/su", |
|
| 202 |
- Mode: 0755 | c_ISREG | c_ISUID, |
|
| 203 |
- Size: 23232, |
|
| 204 |
- ModTime: time.Unix(1355405093, 0), |
|
| 205 |
- Typeflag: TypeReg, |
|
| 206 |
- }, |
|
| 207 |
- fm: 0755 | os.ModeSetuid, |
|
| 208 |
- }, {
|
|
| 209 |
- // setguid. |
|
| 210 |
- h: &Header{
|
|
| 211 |
- Name: "group.txt", |
|
| 212 |
- Mode: 0750 | c_ISREG | c_ISGID, |
|
| 213 |
- Size: 0, |
|
| 214 |
- ModTime: time.Unix(1360602346, 0), |
|
| 215 |
- Typeflag: TypeReg, |
|
| 216 |
- }, |
|
| 217 |
- fm: 0750 | os.ModeSetgid, |
|
| 218 |
- }, {
|
|
| 219 |
- // sticky. |
|
| 220 |
- h: &Header{
|
|
| 221 |
- Name: "sticky.txt", |
|
| 222 |
- Mode: 0600 | c_ISREG | c_ISVTX, |
|
| 223 |
- Size: 7, |
|
| 224 |
- ModTime: time.Unix(1360602540, 0), |
|
| 225 |
- Typeflag: TypeReg, |
|
| 226 |
- }, |
|
| 227 |
- fm: 0600 | os.ModeSticky, |
|
| 228 |
- }, {
|
|
| 229 |
- // hard link. |
|
| 230 |
- h: &Header{
|
|
| 231 |
- Name: "hard.txt", |
|
| 232 |
- Mode: 0644 | c_ISREG, |
|
| 233 |
- Size: 0, |
|
| 234 |
- Linkname: "file.txt", |
|
| 235 |
- ModTime: time.Unix(1360600916, 0), |
|
| 236 |
- Typeflag: TypeLink, |
|
| 237 |
- }, |
|
| 238 |
- fm: 0644, |
|
| 239 |
- }, {
|
|
| 240 |
- // More information. |
|
| 241 |
- h: &Header{
|
|
| 242 |
- Name: "info.txt", |
|
| 243 |
- Mode: 0600 | c_ISREG, |
|
| 244 |
- Size: 0, |
|
| 245 |
- Uid: 1000, |
|
| 246 |
- Gid: 1000, |
|
| 247 |
- ModTime: time.Unix(1360602540, 0), |
|
| 248 |
- Uname: "slartibartfast", |
|
| 249 |
- Gname: "users", |
|
| 250 |
- Typeflag: TypeReg, |
|
| 251 |
- }, |
|
| 252 |
- fm: 0600, |
|
| 253 |
- }} |
|
| 254 |
- |
|
| 255 |
- for i, v := range vectors {
|
|
| 256 |
- fi := v.h.FileInfo() |
|
| 257 |
- h2, err := FileInfoHeader(fi, "") |
|
| 258 |
- if err != nil {
|
|
| 259 |
- t.Error(err) |
|
| 260 |
- continue |
|
| 261 |
- } |
|
| 262 |
- if strings.Contains(fi.Name(), "/") {
|
|
| 263 |
- t.Errorf("FileInfo of %q contains slash: %q", v.h.Name, fi.Name())
|
|
| 264 |
- } |
|
| 265 |
- name := path.Base(v.h.Name) |
|
| 266 |
- if fi.IsDir() {
|
|
| 267 |
- name += "/" |
|
| 268 |
- } |
|
| 269 |
- if got, want := h2.Name, name; got != want {
|
|
| 270 |
- t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
|
|
| 271 |
- } |
|
| 272 |
- if got, want := h2.Size, v.h.Size; got != want {
|
|
| 273 |
- t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
|
|
| 274 |
- } |
|
| 275 |
- if got, want := h2.Uid, v.h.Uid; got != want {
|
|
| 276 |
- t.Errorf("i=%d: Uid: got %d, want %d", i, got, want)
|
|
| 277 |
- } |
|
| 278 |
- if got, want := h2.Gid, v.h.Gid; got != want {
|
|
| 279 |
- t.Errorf("i=%d: Gid: got %d, want %d", i, got, want)
|
|
| 280 |
- } |
|
| 281 |
- if got, want := h2.Uname, v.h.Uname; got != want {
|
|
| 282 |
- t.Errorf("i=%d: Uname: got %q, want %q", i, got, want)
|
|
| 283 |
- } |
|
| 284 |
- if got, want := h2.Gname, v.h.Gname; got != want {
|
|
| 285 |
- t.Errorf("i=%d: Gname: got %q, want %q", i, got, want)
|
|
| 286 |
- } |
|
| 287 |
- if got, want := h2.Linkname, v.h.Linkname; got != want {
|
|
| 288 |
- t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want)
|
|
| 289 |
- } |
|
| 290 |
- if got, want := h2.Typeflag, v.h.Typeflag; got != want {
|
|
| 291 |
- t.Logf("%#v %#v", v.h, fi.Sys())
|
|
| 292 |
- t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want)
|
|
| 293 |
- } |
|
| 294 |
- if got, want := h2.Mode, v.h.Mode; got != want {
|
|
| 295 |
- t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
|
|
| 296 |
- } |
|
| 297 |
- if got, want := fi.Mode(), v.fm; got != want {
|
|
| 298 |
- t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
|
|
| 299 |
- } |
|
| 300 |
- if got, want := h2.AccessTime, v.h.AccessTime; got != want {
|
|
| 301 |
- t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want)
|
|
| 302 |
- } |
|
| 303 |
- if got, want := h2.ChangeTime, v.h.ChangeTime; got != want {
|
|
| 304 |
- t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want)
|
|
| 305 |
- } |
|
| 306 |
- if got, want := h2.ModTime, v.h.ModTime; got != want {
|
|
| 307 |
- t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
|
|
| 308 |
- } |
|
| 309 |
- if sysh, ok := fi.Sys().(*Header); !ok || sysh != v.h {
|
|
| 310 |
- t.Errorf("i=%d: Sys didn't return original *Header", i)
|
|
| 311 |
- } |
|
| 312 |
- } |
|
| 313 |
-} |
| 22 | 21 |
deleted file mode 100644 |
| ... | ... |
@@ -1,647 +0,0 @@ |
| 1 |
-// Copyright 2009 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 |
- "fmt" |
|
| 10 |
- "io" |
|
| 11 |
- "io/ioutil" |
|
| 12 |
- "os" |
|
| 13 |
- "reflect" |
|
| 14 |
- "sort" |
|
| 15 |
- "strings" |
|
| 16 |
- "testing" |
|
| 17 |
- "testing/iotest" |
|
| 18 |
- "time" |
|
| 19 |
-) |
|
| 20 |
- |
|
| 21 |
-// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection. |
|
| 22 |
-func bytestr(offset int, b []byte) string {
|
|
| 23 |
- const rowLen = 32 |
|
| 24 |
- s := fmt.Sprintf("%04x ", offset)
|
|
| 25 |
- for _, ch := range b {
|
|
| 26 |
- switch {
|
|
| 27 |
- case '0' <= ch && ch <= '9', 'A' <= ch && ch <= 'Z', 'a' <= ch && ch <= 'z': |
|
| 28 |
- s += fmt.Sprintf(" %c", ch)
|
|
| 29 |
- default: |
|
| 30 |
- s += fmt.Sprintf(" %02x", ch)
|
|
| 31 |
- } |
|
| 32 |
- } |
|
| 33 |
- return s |
|
| 34 |
-} |
|
| 35 |
- |
|
| 36 |
-// Render a pseudo-diff between two blocks of bytes. |
|
| 37 |
-func bytediff(a []byte, b []byte) string {
|
|
| 38 |
- const rowLen = 32 |
|
| 39 |
- s := fmt.Sprintf("(%d bytes vs. %d bytes)\n", len(a), len(b))
|
|
| 40 |
- for offset := 0; len(a)+len(b) > 0; offset += rowLen {
|
|
| 41 |
- na, nb := rowLen, rowLen |
|
| 42 |
- if na > len(a) {
|
|
| 43 |
- na = len(a) |
|
| 44 |
- } |
|
| 45 |
- if nb > len(b) {
|
|
| 46 |
- nb = len(b) |
|
| 47 |
- } |
|
| 48 |
- sa := bytestr(offset, a[0:na]) |
|
| 49 |
- sb := bytestr(offset, b[0:nb]) |
|
| 50 |
- if sa != sb {
|
|
| 51 |
- s += fmt.Sprintf("-%v\n+%v\n", sa, sb)
|
|
| 52 |
- } |
|
| 53 |
- a = a[na:] |
|
| 54 |
- b = b[nb:] |
|
| 55 |
- } |
|
| 56 |
- return s |
|
| 57 |
-} |
|
| 58 |
- |
|
| 59 |
-func TestWriter(t *testing.T) {
|
|
| 60 |
- type entry struct {
|
|
| 61 |
- header *Header |
|
| 62 |
- contents string |
|
| 63 |
- } |
|
| 64 |
- |
|
| 65 |
- vectors := []struct {
|
|
| 66 |
- file string // filename of expected output |
|
| 67 |
- entries []*entry |
|
| 68 |
- }{{
|
|
| 69 |
- // The writer test file was produced with this command: |
|
| 70 |
- // tar (GNU tar) 1.26 |
|
| 71 |
- // ln -s small.txt link.txt |
|
| 72 |
- // tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt |
|
| 73 |
- file: "testdata/writer.tar", |
|
| 74 |
- entries: []*entry{{
|
|
| 75 |
- header: &Header{
|
|
| 76 |
- Name: "small.txt", |
|
| 77 |
- Mode: 0640, |
|
| 78 |
- Uid: 73025, |
|
| 79 |
- Gid: 5000, |
|
| 80 |
- Size: 5, |
|
| 81 |
- ModTime: time.Unix(1246508266, 0), |
|
| 82 |
- Typeflag: '0', |
|
| 83 |
- Uname: "dsymonds", |
|
| 84 |
- Gname: "eng", |
|
| 85 |
- }, |
|
| 86 |
- contents: "Kilts", |
|
| 87 |
- }, {
|
|
| 88 |
- header: &Header{
|
|
| 89 |
- Name: "small2.txt", |
|
| 90 |
- Mode: 0640, |
|
| 91 |
- Uid: 73025, |
|
| 92 |
- Gid: 5000, |
|
| 93 |
- Size: 11, |
|
| 94 |
- ModTime: time.Unix(1245217492, 0), |
|
| 95 |
- Typeflag: '0', |
|
| 96 |
- Uname: "dsymonds", |
|
| 97 |
- Gname: "eng", |
|
| 98 |
- }, |
|
| 99 |
- contents: "Google.com\n", |
|
| 100 |
- }, {
|
|
| 101 |
- header: &Header{
|
|
| 102 |
- Name: "link.txt", |
|
| 103 |
- Mode: 0777, |
|
| 104 |
- Uid: 1000, |
|
| 105 |
- Gid: 1000, |
|
| 106 |
- Size: 0, |
|
| 107 |
- ModTime: time.Unix(1314603082, 0), |
|
| 108 |
- Typeflag: '2', |
|
| 109 |
- Linkname: "small.txt", |
|
| 110 |
- Uname: "strings", |
|
| 111 |
- Gname: "strings", |
|
| 112 |
- }, |
|
| 113 |
- // no contents |
|
| 114 |
- }}, |
|
| 115 |
- }, {
|
|
| 116 |
- // The truncated test file was produced using these commands: |
|
| 117 |
- // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt |
|
| 118 |
- // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar |
|
| 119 |
- file: "testdata/writer-big.tar", |
|
| 120 |
- entries: []*entry{{
|
|
| 121 |
- header: &Header{
|
|
| 122 |
- Name: "tmp/16gig.txt", |
|
| 123 |
- Mode: 0640, |
|
| 124 |
- Uid: 73025, |
|
| 125 |
- Gid: 5000, |
|
| 126 |
- Size: 16 << 30, |
|
| 127 |
- ModTime: time.Unix(1254699560, 0), |
|
| 128 |
- Typeflag: '0', |
|
| 129 |
- Uname: "dsymonds", |
|
| 130 |
- Gname: "eng", |
|
| 131 |
- }, |
|
| 132 |
- // fake contents |
|
| 133 |
- contents: strings.Repeat("\x00", 4<<10),
|
|
| 134 |
- }}, |
|
| 135 |
- }, {
|
|
| 136 |
- // This truncated file was produced using this library. |
|
| 137 |
- // It was verified to work with GNU tar 1.27.1 and BSD tar 3.1.2. |
|
| 138 |
- // dd if=/dev/zero bs=1G count=16 >> writer-big-long.tar |
|
| 139 |
- // gnutar -xvf writer-big-long.tar |
|
| 140 |
- // bsdtar -xvf writer-big-long.tar |
|
| 141 |
- // |
|
| 142 |
- // This file is in PAX format. |
|
| 143 |
- file: "testdata/writer-big-long.tar", |
|
| 144 |
- entries: []*entry{{
|
|
| 145 |
- header: &Header{
|
|
| 146 |
- Name: strings.Repeat("longname/", 15) + "16gig.txt",
|
|
| 147 |
- Mode: 0644, |
|
| 148 |
- Uid: 1000, |
|
| 149 |
- Gid: 1000, |
|
| 150 |
- Size: 16 << 30, |
|
| 151 |
- ModTime: time.Unix(1399583047, 0), |
|
| 152 |
- Typeflag: '0', |
|
| 153 |
- Uname: "guillaume", |
|
| 154 |
- Gname: "guillaume", |
|
| 155 |
- }, |
|
| 156 |
- // fake contents |
|
| 157 |
- contents: strings.Repeat("\x00", 4<<10),
|
|
| 158 |
- }}, |
|
| 159 |
- }, {
|
|
| 160 |
- // TODO(dsnet): The Writer output should match the following file. |
|
| 161 |
- // To fix an issue (see https://golang.org/issue/12594), we disabled |
|
| 162 |
- // prefix support, which alters the generated output. |
|
| 163 |
- /* |
|
| 164 |
- // This file was produced using gnu tar 1.17 |
|
| 165 |
- // gnutar -b 4 --format=ustar (longname/)*15 + file.txt |
|
| 166 |
- file: "testdata/ustar.tar" |
|
| 167 |
- */ |
|
| 168 |
- file: "testdata/ustar.issue12594.tar", // This is a valid tar file, but not expected |
|
| 169 |
- entries: []*entry{{
|
|
| 170 |
- header: &Header{
|
|
| 171 |
- Name: strings.Repeat("longname/", 15) + "file.txt",
|
|
| 172 |
- Mode: 0644, |
|
| 173 |
- Uid: 0765, |
|
| 174 |
- Gid: 024, |
|
| 175 |
- Size: 06, |
|
| 176 |
- ModTime: time.Unix(1360135598, 0), |
|
| 177 |
- Typeflag: '0', |
|
| 178 |
- Uname: "shane", |
|
| 179 |
- Gname: "staff", |
|
| 180 |
- }, |
|
| 181 |
- contents: "hello\n", |
|
| 182 |
- }}, |
|
| 183 |
- }, {
|
|
| 184 |
- // This file was produced using gnu tar 1.26 |
|
| 185 |
- // echo "Slartibartfast" > file.txt |
|
| 186 |
- // ln file.txt hard.txt |
|
| 187 |
- // tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt |
|
| 188 |
- file: "testdata/hardlink.tar", |
|
| 189 |
- entries: []*entry{{
|
|
| 190 |
- header: &Header{
|
|
| 191 |
- Name: "file.txt", |
|
| 192 |
- Mode: 0644, |
|
| 193 |
- Uid: 1000, |
|
| 194 |
- Gid: 100, |
|
| 195 |
- Size: 15, |
|
| 196 |
- ModTime: time.Unix(1425484303, 0), |
|
| 197 |
- Typeflag: '0', |
|
| 198 |
- Uname: "vbatts", |
|
| 199 |
- Gname: "users", |
|
| 200 |
- }, |
|
| 201 |
- contents: "Slartibartfast\n", |
|
| 202 |
- }, {
|
|
| 203 |
- header: &Header{
|
|
| 204 |
- Name: "hard.txt", |
|
| 205 |
- Mode: 0644, |
|
| 206 |
- Uid: 1000, |
|
| 207 |
- Gid: 100, |
|
| 208 |
- Size: 0, |
|
| 209 |
- ModTime: time.Unix(1425484303, 0), |
|
| 210 |
- Typeflag: '1', |
|
| 211 |
- Linkname: "file.txt", |
|
| 212 |
- Uname: "vbatts", |
|
| 213 |
- Gname: "users", |
|
| 214 |
- }, |
|
| 215 |
- // no contents |
|
| 216 |
- }}, |
|
| 217 |
- }} |
|
| 218 |
- |
|
| 219 |
-testLoop: |
|
| 220 |
- for i, v := range vectors {
|
|
| 221 |
- expected, err := ioutil.ReadFile(v.file) |
|
| 222 |
- if err != nil {
|
|
| 223 |
- t.Errorf("test %d: Unexpected error: %v", i, err)
|
|
| 224 |
- continue |
|
| 225 |
- } |
|
| 226 |
- |
|
| 227 |
- buf := new(bytes.Buffer) |
|
| 228 |
- tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB |
|
| 229 |
- big := false |
|
| 230 |
- for j, entry := range v.entries {
|
|
| 231 |
- big = big || entry.header.Size > 1<<10 |
|
| 232 |
- if err := tw.WriteHeader(entry.header); err != nil {
|
|
| 233 |
- t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
|
|
| 234 |
- continue testLoop |
|
| 235 |
- } |
|
| 236 |
- if _, err := io.WriteString(tw, entry.contents); err != nil {
|
|
| 237 |
- t.Errorf("test %d, entry %d: Failed writing contents: %v", i, j, err)
|
|
| 238 |
- continue testLoop |
|
| 239 |
- } |
|
| 240 |
- } |
|
| 241 |
- // Only interested in Close failures for the small tests. |
|
| 242 |
- if err := tw.Close(); err != nil && !big {
|
|
| 243 |
- t.Errorf("test %d: Failed closing archive: %v", i, err)
|
|
| 244 |
- continue testLoop |
|
| 245 |
- } |
|
| 246 |
- |
|
| 247 |
- actual := buf.Bytes() |
|
| 248 |
- if !bytes.Equal(expected, actual) {
|
|
| 249 |
- t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v",
|
|
| 250 |
- i, bytediff(expected, actual)) |
|
| 251 |
- } |
|
| 252 |
- if testing.Short() { // The second test is expensive.
|
|
| 253 |
- break |
|
| 254 |
- } |
|
| 255 |
- } |
|
| 256 |
-} |
|
| 257 |
- |
|
| 258 |
-func TestPax(t *testing.T) {
|
|
| 259 |
- // Create an archive with a large name |
|
| 260 |
- fileinfo, err := os.Stat("testdata/small.txt")
|
|
| 261 |
- if err != nil {
|
|
| 262 |
- t.Fatal(err) |
|
| 263 |
- } |
|
| 264 |
- hdr, err := FileInfoHeader(fileinfo, "") |
|
| 265 |
- if err != nil {
|
|
| 266 |
- t.Fatalf("os.Stat: %v", err)
|
|
| 267 |
- } |
|
| 268 |
- // Force a PAX long name to be written |
|
| 269 |
- longName := strings.Repeat("ab", 100)
|
|
| 270 |
- contents := strings.Repeat(" ", int(hdr.Size))
|
|
| 271 |
- hdr.Name = longName |
|
| 272 |
- var buf bytes.Buffer |
|
| 273 |
- writer := NewWriter(&buf) |
|
| 274 |
- if err := writer.WriteHeader(hdr); err != nil {
|
|
| 275 |
- t.Fatal(err) |
|
| 276 |
- } |
|
| 277 |
- if _, err = writer.Write([]byte(contents)); err != nil {
|
|
| 278 |
- t.Fatal(err) |
|
| 279 |
- } |
|
| 280 |
- if err := writer.Close(); err != nil {
|
|
| 281 |
- t.Fatal(err) |
|
| 282 |
- } |
|
| 283 |
- // Simple test to make sure PAX extensions are in effect |
|
| 284 |
- if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
|
|
| 285 |
- t.Fatal("Expected at least one PAX header to be written.")
|
|
| 286 |
- } |
|
| 287 |
- // Test that we can get a long name back out of the archive. |
|
| 288 |
- reader := NewReader(&buf) |
|
| 289 |
- hdr, err = reader.Next() |
|
| 290 |
- if err != nil {
|
|
| 291 |
- t.Fatal(err) |
|
| 292 |
- } |
|
| 293 |
- if hdr.Name != longName {
|
|
| 294 |
- t.Fatal("Couldn't recover long file name")
|
|
| 295 |
- } |
|
| 296 |
-} |
|
| 297 |
- |
|
| 298 |
-func TestPaxSymlink(t *testing.T) {
|
|
| 299 |
- // Create an archive with a large linkname |
|
| 300 |
- fileinfo, err := os.Stat("testdata/small.txt")
|
|
| 301 |
- if err != nil {
|
|
| 302 |
- t.Fatal(err) |
|
| 303 |
- } |
|
| 304 |
- hdr, err := FileInfoHeader(fileinfo, "") |
|
| 305 |
- hdr.Typeflag = TypeSymlink |
|
| 306 |
- if err != nil {
|
|
| 307 |
- t.Fatalf("os.Stat:1 %v", err)
|
|
| 308 |
- } |
|
| 309 |
- // Force a PAX long linkname to be written |
|
| 310 |
- longLinkname := strings.Repeat("1234567890/1234567890", 10)
|
|
| 311 |
- hdr.Linkname = longLinkname |
|
| 312 |
- |
|
| 313 |
- hdr.Size = 0 |
|
| 314 |
- var buf bytes.Buffer |
|
| 315 |
- writer := NewWriter(&buf) |
|
| 316 |
- if err := writer.WriteHeader(hdr); err != nil {
|
|
| 317 |
- t.Fatal(err) |
|
| 318 |
- } |
|
| 319 |
- if err := writer.Close(); err != nil {
|
|
| 320 |
- t.Fatal(err) |
|
| 321 |
- } |
|
| 322 |
- // Simple test to make sure PAX extensions are in effect |
|
| 323 |
- if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
|
|
| 324 |
- t.Fatal("Expected at least one PAX header to be written.")
|
|
| 325 |
- } |
|
| 326 |
- // Test that we can get a long name back out of the archive. |
|
| 327 |
- reader := NewReader(&buf) |
|
| 328 |
- hdr, err = reader.Next() |
|
| 329 |
- if err != nil {
|
|
| 330 |
- t.Fatal(err) |
|
| 331 |
- } |
|
| 332 |
- if hdr.Linkname != longLinkname {
|
|
| 333 |
- t.Fatal("Couldn't recover long link name")
|
|
| 334 |
- } |
|
| 335 |
-} |
|
| 336 |
- |
|
| 337 |
-func TestPaxNonAscii(t *testing.T) {
|
|
| 338 |
- // Create an archive with non ascii. These should trigger a pax header |
|
| 339 |
- // because pax headers have a defined utf-8 encoding. |
|
| 340 |
- fileinfo, err := os.Stat("testdata/small.txt")
|
|
| 341 |
- if err != nil {
|
|
| 342 |
- t.Fatal(err) |
|
| 343 |
- } |
|
| 344 |
- |
|
| 345 |
- hdr, err := FileInfoHeader(fileinfo, "") |
|
| 346 |
- if err != nil {
|
|
| 347 |
- t.Fatalf("os.Stat:1 %v", err)
|
|
| 348 |
- } |
|
| 349 |
- |
|
| 350 |
- // some sample data |
|
| 351 |
- chineseFilename := "文件名" |
|
| 352 |
- chineseGroupname := "組" |
|
| 353 |
- chineseUsername := "用戶名" |
|
| 354 |
- |
|
| 355 |
- hdr.Name = chineseFilename |
|
| 356 |
- hdr.Gname = chineseGroupname |
|
| 357 |
- hdr.Uname = chineseUsername |
|
| 358 |
- |
|
| 359 |
- contents := strings.Repeat(" ", int(hdr.Size))
|
|
| 360 |
- |
|
| 361 |
- var buf bytes.Buffer |
|
| 362 |
- writer := NewWriter(&buf) |
|
| 363 |
- if err := writer.WriteHeader(hdr); err != nil {
|
|
| 364 |
- t.Fatal(err) |
|
| 365 |
- } |
|
| 366 |
- if _, err = writer.Write([]byte(contents)); err != nil {
|
|
| 367 |
- t.Fatal(err) |
|
| 368 |
- } |
|
| 369 |
- if err := writer.Close(); err != nil {
|
|
| 370 |
- t.Fatal(err) |
|
| 371 |
- } |
|
| 372 |
- // Simple test to make sure PAX extensions are in effect |
|
| 373 |
- if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
|
|
| 374 |
- t.Fatal("Expected at least one PAX header to be written.")
|
|
| 375 |
- } |
|
| 376 |
- // Test that we can get a long name back out of the archive. |
|
| 377 |
- reader := NewReader(&buf) |
|
| 378 |
- hdr, err = reader.Next() |
|
| 379 |
- if err != nil {
|
|
| 380 |
- t.Fatal(err) |
|
| 381 |
- } |
|
| 382 |
- if hdr.Name != chineseFilename {
|
|
| 383 |
- t.Fatal("Couldn't recover unicode name")
|
|
| 384 |
- } |
|
| 385 |
- if hdr.Gname != chineseGroupname {
|
|
| 386 |
- t.Fatal("Couldn't recover unicode group")
|
|
| 387 |
- } |
|
| 388 |
- if hdr.Uname != chineseUsername {
|
|
| 389 |
- t.Fatal("Couldn't recover unicode user")
|
|
| 390 |
- } |
|
| 391 |
-} |
|
| 392 |
- |
|
| 393 |
-func TestPaxXattrs(t *testing.T) {
|
|
| 394 |
- xattrs := map[string]string{
|
|
| 395 |
- "user.key": "value", |
|
| 396 |
- } |
|
| 397 |
- |
|
| 398 |
- // Create an archive with an xattr |
|
| 399 |
- fileinfo, err := os.Stat("testdata/small.txt")
|
|
| 400 |
- if err != nil {
|
|
| 401 |
- t.Fatal(err) |
|
| 402 |
- } |
|
| 403 |
- hdr, err := FileInfoHeader(fileinfo, "") |
|
| 404 |
- if err != nil {
|
|
| 405 |
- t.Fatalf("os.Stat: %v", err)
|
|
| 406 |
- } |
|
| 407 |
- contents := "Kilts" |
|
| 408 |
- hdr.Xattrs = xattrs |
|
| 409 |
- var buf bytes.Buffer |
|
| 410 |
- writer := NewWriter(&buf) |
|
| 411 |
- if err := writer.WriteHeader(hdr); err != nil {
|
|
| 412 |
- t.Fatal(err) |
|
| 413 |
- } |
|
| 414 |
- if _, err = writer.Write([]byte(contents)); err != nil {
|
|
| 415 |
- t.Fatal(err) |
|
| 416 |
- } |
|
| 417 |
- if err := writer.Close(); err != nil {
|
|
| 418 |
- t.Fatal(err) |
|
| 419 |
- } |
|
| 420 |
- // Test that we can get the xattrs back out of the archive. |
|
| 421 |
- reader := NewReader(&buf) |
|
| 422 |
- hdr, err = reader.Next() |
|
| 423 |
- if err != nil {
|
|
| 424 |
- t.Fatal(err) |
|
| 425 |
- } |
|
| 426 |
- if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
|
|
| 427 |
- t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
|
|
| 428 |
- hdr.Xattrs, xattrs) |
|
| 429 |
- } |
|
| 430 |
-} |
|
| 431 |
- |
|
| 432 |
-func TestPaxHeadersSorted(t *testing.T) {
|
|
| 433 |
- fileinfo, err := os.Stat("testdata/small.txt")
|
|
| 434 |
- if err != nil {
|
|
| 435 |
- t.Fatal(err) |
|
| 436 |
- } |
|
| 437 |
- hdr, err := FileInfoHeader(fileinfo, "") |
|
| 438 |
- if err != nil {
|
|
| 439 |
- t.Fatalf("os.Stat: %v", err)
|
|
| 440 |
- } |
|
| 441 |
- contents := strings.Repeat(" ", int(hdr.Size))
|
|
| 442 |
- |
|
| 443 |
- hdr.Xattrs = map[string]string{
|
|
| 444 |
- "foo": "foo", |
|
| 445 |
- "bar": "bar", |
|
| 446 |
- "baz": "baz", |
|
| 447 |
- "qux": "qux", |
|
| 448 |
- } |
|
| 449 |
- |
|
| 450 |
- var buf bytes.Buffer |
|
| 451 |
- writer := NewWriter(&buf) |
|
| 452 |
- if err := writer.WriteHeader(hdr); err != nil {
|
|
| 453 |
- t.Fatal(err) |
|
| 454 |
- } |
|
| 455 |
- if _, err = writer.Write([]byte(contents)); err != nil {
|
|
| 456 |
- t.Fatal(err) |
|
| 457 |
- } |
|
| 458 |
- if err := writer.Close(); err != nil {
|
|
| 459 |
- t.Fatal(err) |
|
| 460 |
- } |
|
| 461 |
- // Simple test to make sure PAX extensions are in effect |
|
| 462 |
- if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
|
|
| 463 |
- t.Fatal("Expected at least one PAX header to be written.")
|
|
| 464 |
- } |
|
| 465 |
- |
|
| 466 |
- // xattr bar should always appear before others |
|
| 467 |
- indices := []int{
|
|
| 468 |
- bytes.Index(buf.Bytes(), []byte("bar=bar")),
|
|
| 469 |
- bytes.Index(buf.Bytes(), []byte("baz=baz")),
|
|
| 470 |
- bytes.Index(buf.Bytes(), []byte("foo=foo")),
|
|
| 471 |
- bytes.Index(buf.Bytes(), []byte("qux=qux")),
|
|
| 472 |
- } |
|
| 473 |
- if !sort.IntsAreSorted(indices) {
|
|
| 474 |
- t.Fatal("PAX headers are not sorted")
|
|
| 475 |
- } |
|
| 476 |
-} |
|
| 477 |
- |
|
| 478 |
-func TestUSTARLongName(t *testing.T) {
|
|
| 479 |
- // Create an archive with a path that failed to split with USTAR extension in previous versions. |
|
| 480 |
- fileinfo, err := os.Stat("testdata/small.txt")
|
|
| 481 |
- if err != nil {
|
|
| 482 |
- t.Fatal(err) |
|
| 483 |
- } |
|
| 484 |
- hdr, err := FileInfoHeader(fileinfo, "") |
|
| 485 |
- hdr.Typeflag = TypeDir |
|
| 486 |
- if err != nil {
|
|
| 487 |
- t.Fatalf("os.Stat:1 %v", err)
|
|
| 488 |
- } |
|
| 489 |
- // Force a PAX long name to be written. The name was taken from a practical example |
|
| 490 |
- // that fails and replaced ever char through numbers to anonymize the sample. |
|
| 491 |
- 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/" |
|
| 492 |
- hdr.Name = longName |
|
| 493 |
- |
|
| 494 |
- hdr.Size = 0 |
|
| 495 |
- var buf bytes.Buffer |
|
| 496 |
- writer := NewWriter(&buf) |
|
| 497 |
- if err := writer.WriteHeader(hdr); err != nil {
|
|
| 498 |
- t.Fatal(err) |
|
| 499 |
- } |
|
| 500 |
- if err := writer.Close(); err != nil {
|
|
| 501 |
- t.Fatal(err) |
|
| 502 |
- } |
|
| 503 |
- // Test that we can get a long name back out of the archive. |
|
| 504 |
- reader := NewReader(&buf) |
|
| 505 |
- hdr, err = reader.Next() |
|
| 506 |
- if err != nil {
|
|
| 507 |
- t.Fatal(err) |
|
| 508 |
- } |
|
| 509 |
- if hdr.Name != longName {
|
|
| 510 |
- t.Fatal("Couldn't recover long name")
|
|
| 511 |
- } |
|
| 512 |
-} |
|
| 513 |
- |
|
| 514 |
-func TestValidTypeflagWithPAXHeader(t *testing.T) {
|
|
| 515 |
- var buffer bytes.Buffer |
|
| 516 |
- tw := NewWriter(&buffer) |
|
| 517 |
- |
|
| 518 |
- fileName := strings.Repeat("ab", 100)
|
|
| 519 |
- |
|
| 520 |
- hdr := &Header{
|
|
| 521 |
- Name: fileName, |
|
| 522 |
- Size: 4, |
|
| 523 |
- Typeflag: 0, |
|
| 524 |
- } |
|
| 525 |
- if err := tw.WriteHeader(hdr); err != nil {
|
|
| 526 |
- t.Fatalf("Failed to write header: %s", err)
|
|
| 527 |
- } |
|
| 528 |
- if _, err := tw.Write([]byte("fooo")); err != nil {
|
|
| 529 |
- t.Fatalf("Failed to write the file's data: %s", err)
|
|
| 530 |
- } |
|
| 531 |
- tw.Close() |
|
| 532 |
- |
|
| 533 |
- tr := NewReader(&buffer) |
|
| 534 |
- |
|
| 535 |
- for {
|
|
| 536 |
- header, err := tr.Next() |
|
| 537 |
- if err == io.EOF {
|
|
| 538 |
- break |
|
| 539 |
- } |
|
| 540 |
- if err != nil {
|
|
| 541 |
- t.Fatalf("Failed to read header: %s", err)
|
|
| 542 |
- } |
|
| 543 |
- if header.Typeflag != 0 {
|
|
| 544 |
- t.Fatalf("Typeflag should've been 0, found %d", header.Typeflag)
|
|
| 545 |
- } |
|
| 546 |
- } |
|
| 547 |
-} |
|
| 548 |
- |
|
| 549 |
-func TestWriteAfterClose(t *testing.T) {
|
|
| 550 |
- var buffer bytes.Buffer |
|
| 551 |
- tw := NewWriter(&buffer) |
|
| 552 |
- |
|
| 553 |
- hdr := &Header{
|
|
| 554 |
- Name: "small.txt", |
|
| 555 |
- Size: 5, |
|
| 556 |
- } |
|
| 557 |
- if err := tw.WriteHeader(hdr); err != nil {
|
|
| 558 |
- t.Fatalf("Failed to write header: %s", err)
|
|
| 559 |
- } |
|
| 560 |
- tw.Close() |
|
| 561 |
- if _, err := tw.Write([]byte("Kilts")); err != ErrWriteAfterClose {
|
|
| 562 |
- t.Fatalf("Write: got %v; want ErrWriteAfterClose", err)
|
|
| 563 |
- } |
|
| 564 |
-} |
|
| 565 |
- |
|
| 566 |
-func TestSplitUSTARPath(t *testing.T) {
|
|
| 567 |
- sr := strings.Repeat |
|
| 568 |
- |
|
| 569 |
- vectors := []struct {
|
|
| 570 |
- input string // Input path |
|
| 571 |
- prefix string // Expected output prefix |
|
| 572 |
- suffix string // Expected output suffix |
|
| 573 |
- ok bool // Split success? |
|
| 574 |
- }{
|
|
| 575 |
- {"", "", "", false},
|
|
| 576 |
- {"abc", "", "", false},
|
|
| 577 |
- {"用戶名", "", "", false},
|
|
| 578 |
- {sr("a", nameSize), "", "", false},
|
|
| 579 |
- {sr("a", nameSize) + "/", "", "", false},
|
|
| 580 |
- {sr("a", nameSize) + "/a", sr("a", nameSize), "a", true},
|
|
| 581 |
- {sr("a", prefixSize) + "/", "", "", false},
|
|
| 582 |
- {sr("a", prefixSize) + "/a", sr("a", prefixSize), "a", true},
|
|
| 583 |
- {sr("a", nameSize+1), "", "", false},
|
|
| 584 |
- {sr("/", nameSize+1), sr("/", nameSize-1), "/", true},
|
|
| 585 |
- {sr("a", prefixSize) + "/" + sr("b", nameSize),
|
|
| 586 |
- sr("a", prefixSize), sr("b", nameSize), true},
|
|
| 587 |
- {sr("a", prefixSize) + "//" + sr("b", nameSize), "", "", false},
|
|
| 588 |
- {sr("a/", nameSize), sr("a/", 77) + "a", sr("a/", 22), true},
|
|
| 589 |
- } |
|
| 590 |
- |
|
| 591 |
- for _, v := range vectors {
|
|
| 592 |
- prefix, suffix, ok := splitUSTARPath(v.input) |
|
| 593 |
- if prefix != v.prefix || suffix != v.suffix || ok != v.ok {
|
|
| 594 |
- t.Errorf("splitUSTARPath(%q):\ngot (%q, %q, %v)\nwant (%q, %q, %v)",
|
|
| 595 |
- v.input, prefix, suffix, ok, v.prefix, v.suffix, v.ok) |
|
| 596 |
- } |
|
| 597 |
- } |
|
| 598 |
-} |
|
| 599 |
- |
|
| 600 |
-// TestIssue12594 tests that the Writer does not attempt to populate the prefix |
|
| 601 |
-// field when encoding a header in the GNU format. The prefix field is valid |
|
| 602 |
-// in USTAR and PAX, but not GNU. |
|
| 603 |
-func TestIssue12594(t *testing.T) {
|
|
| 604 |
- names := []string{
|
|
| 605 |
- "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", |
|
| 606 |
- "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", |
|
| 607 |
- "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", |
|
| 608 |
- "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", |
|
| 609 |
- "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000/file.txt", |
|
| 610 |
- "/home/support/.openoffice.org/3/user/uno_packages/cache/registry/com.sun.star.comp.deployment.executable.PackageRegistryBackend", |
|
| 611 |
- } |
|
| 612 |
- |
|
| 613 |
- for i, name := range names {
|
|
| 614 |
- var b bytes.Buffer |
|
| 615 |
- |
|
| 616 |
- tw := NewWriter(&b) |
|
| 617 |
- if err := tw.WriteHeader(&Header{
|
|
| 618 |
- Name: name, |
|
| 619 |
- Uid: 1 << 25, // Prevent USTAR format |
|
| 620 |
- }); err != nil {
|
|
| 621 |
- t.Errorf("test %d, unexpected WriteHeader error: %v", i, err)
|
|
| 622 |
- } |
|
| 623 |
- if err := tw.Close(); err != nil {
|
|
| 624 |
- t.Errorf("test %d, unexpected Close error: %v", i, err)
|
|
| 625 |
- } |
|
| 626 |
- |
|
| 627 |
- // The prefix field should never appear in the GNU format. |
|
| 628 |
- var blk block |
|
| 629 |
- copy(blk[:], b.Bytes()) |
|
| 630 |
- prefix := string(blk.USTAR().Prefix()) |
|
| 631 |
- if i := strings.IndexByte(prefix, 0); i >= 0 {
|
|
| 632 |
- prefix = prefix[:i] // Truncate at the NUL terminator |
|
| 633 |
- } |
|
| 634 |
- if blk.GetFormat() == formatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
|
|
| 635 |
- t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
|
|
| 636 |
- } |
|
| 637 |
- |
|
| 638 |
- tr := NewReader(&b) |
|
| 639 |
- hdr, err := tr.Next() |
|
| 640 |
- if err != nil {
|
|
| 641 |
- t.Errorf("test %d, unexpected Next error: %v", i, err)
|
|
| 642 |
- } |
|
| 643 |
- if hdr.Name != name {
|
|
| 644 |
- t.Errorf("test %d, hdr.Name = %s, want %s", i, hdr.Name, name)
|
|
| 645 |
- } |
|
| 646 |
- } |
|
| 647 |
-} |
| ... | ... |
@@ -646,7 +646,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, |
| 646 | 646 |
} |
| 647 | 647 |
|
| 648 | 648 |
if err = d.storeUpdate(endpoint); err != nil {
|
| 649 |
- return fmt.Errorf("failed to save endpoint %s to store: %v", endpoint.id[0:7], err)
|
|
| 649 |
+ logrus.Errorf("Failed to save endpoint %s to store: %v", endpoint.id[0:7], err)
|
|
| 650 | 650 |
} |
| 651 | 651 |
|
| 652 | 652 |
return nil |
| ... | ... |
@@ -995,6 +995,10 @@ func (n *network) delete(force bool) error {
|
| 995 | 995 |
logrus.Errorf("Failed leaving network %s from the agent cluster: %v", n.Name(), err)
|
| 996 | 996 |
} |
| 997 | 997 |
|
| 998 |
+ // Cleanup the service discovery for this network |
|
| 999 |
+ c.cleanupServiceDiscovery(n.ID()) |
|
| 1000 |
+ |
|
| 1001 |
+ // Cleanup the load balancer |
|
| 998 | 1002 |
c.cleanupServiceBindings(n.ID()) |
| 999 | 1003 |
|
| 1000 | 1004 |
removeFromStore: |
| ... | ... |
@@ -499,7 +499,10 @@ func (nDB *NetworkDB) deleteNodeNetworkEntries(nid, node string) {
|
| 499 | 499 |
// without doing a delete of all the objects |
| 500 | 500 |
entry.ltime++ |
| 501 | 501 |
} |
| 502 |
- nDB.createOrUpdateEntry(nid, tname, key, entry) |
|
| 502 |
+ |
|
| 503 |
+ if !oldEntry.deleting {
|
|
| 504 |
+ nDB.createOrUpdateEntry(nid, tname, key, entry) |
|
| 505 |
+ } |
|
| 503 | 506 |
} else {
|
| 504 | 507 |
// the local node is leaving the network, all the entries of remote nodes can be safely removed |
| 505 | 508 |
nDB.deleteEntry(nid, tname, key) |
| ... | ... |
@@ -161,6 +161,19 @@ func (c *controller) getLBIndex(sid, nid string, ingressPorts []*PortConfig) int |
| 161 | 161 |
return int(lb.fwMark) |
| 162 | 162 |
} |
| 163 | 163 |
|
| 164 |
+// cleanupServiceDiscovery when the network is being deleted, erase all the associated service discovery records |
|
| 165 |
+func (c *controller) cleanupServiceDiscovery(cleanupNID string) {
|
|
| 166 |
+ c.Lock() |
|
| 167 |
+ defer c.Unlock() |
|
| 168 |
+ if cleanupNID == "" {
|
|
| 169 |
+ logrus.Debugf("cleanupServiceDiscovery for all networks")
|
|
| 170 |
+ c.svcRecords = make(map[string]svcInfo) |
|
| 171 |
+ return |
|
| 172 |
+ } |
|
| 173 |
+ logrus.Debugf("cleanupServiceDiscovery for network:%s", cleanupNID)
|
|
| 174 |
+ delete(c.svcRecords, cleanupNID) |
|
| 175 |
+} |
|
| 176 |
+ |
|
| 164 | 177 |
func (c *controller) cleanupServiceBindings(cleanupNID string) {
|
| 165 | 178 |
var cleanupFuncs []func() |
| 166 | 179 |
|
| ... | ... |
@@ -184,15 +197,6 @@ func (c *controller) cleanupServiceBindings(cleanupNID string) {
|
| 184 | 184 |
continue |
| 185 | 185 |
} |
| 186 | 186 |
|
| 187 |
- // The network is being deleted, erase all the associated service discovery records |
|
| 188 |
- // TODO(fcrisciani) separate the Load Balancer from the Service discovery, this operation |
|
| 189 |
- // can be done safely here, but the rmServiceBinding is still keeping consistency in the |
|
| 190 |
- // data structures that are tracking the endpoint to IP mapping. |
|
| 191 |
- c.Lock() |
|
| 192 |
- logrus.Debugf("cleanupServiceBindings erasing the svcRecords for %s", nid)
|
|
| 193 |
- delete(c.svcRecords, nid) |
|
| 194 |
- c.Unlock() |
|
| 195 |
- |
|
| 196 | 187 |
for eid, ip := range lb.backEnds {
|
| 197 | 188 |
epID := eid |
| 198 | 189 |
epIP := ip |