OLD | NEW |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package tar | 5 package tar |
6 | 6 |
7 // TODO(dsymonds): | 7 // TODO(dsymonds): |
8 // - catch more errors (no first header, write after close, etc.) | 8 // - catch more errors (no first header, write after close, etc.) |
9 | 9 |
10 import ( | 10 import ( |
11 "io" | 11 "io" |
12 "os" | 12 "os" |
13 "strconv" | 13 "strconv" |
14 "strings" | |
15 ) | 14 ) |
16 | 15 |
17 var ( | 16 var ( |
18 ErrWriteTooLong = os.NewError("write too long") | 17 ErrWriteTooLong = os.NewError("write too long") |
19 ErrFieldTooLong = os.NewError("header field too long") | 18 ErrFieldTooLong = os.NewError("header field too long") |
20 ErrWriteAfterClose = os.NewError("write after close") | 19 ErrWriteAfterClose = os.NewError("write after close") |
21 ) | 20 ) |
22 | 21 |
23 // A Writer provides sequential writing of a tar archive in POSIX.1 format. | 22 // A Writer provides sequential writing of a tar archive in POSIX.1 format. |
24 // A tar archive consists of a sequence of files. | 23 // A tar archive consists of a sequence of files. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 } | 64 } |
66 | 65 |
67 // Write s into b, terminating it with a NUL if there is room. | 66 // Write s into b, terminating it with a NUL if there is room. |
68 func (tw *Writer) cString(b []byte, s string) { | 67 func (tw *Writer) cString(b []byte, s string) { |
69 if len(s) > len(b) { | 68 if len(s) > len(b) { |
70 if tw.err == nil { | 69 if tw.err == nil { |
71 tw.err = ErrFieldTooLong | 70 tw.err = ErrFieldTooLong |
72 } | 71 } |
73 return | 72 return |
74 } | 73 } |
75 » for i, ch := range strings.Bytes(s) { | 74 » for i, ch := range []byte(s) { |
76 b[i] = ch | 75 b[i] = ch |
77 } | 76 } |
78 if len(s) < len(b) { | 77 if len(s) < len(b) { |
79 b[len(s)] = 0 | 78 b[len(s)] = 0 |
80 } | 79 } |
81 } | 80 } |
82 | 81 |
83 // Encode x as an octal ASCII string and write it into b with leading zeros. | 82 // Encode x as an octal ASCII string and write it into b with leading zeros. |
84 func (tw *Writer) octal(b []byte, x int64) { | 83 func (tw *Writer) octal(b []byte, x int64) { |
85 s := strconv.Itob64(x, 8) | 84 s := strconv.Itob64(x, 8) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 return tw.err | 120 return tw.err |
122 } | 121 } |
123 | 122 |
124 tw.nb = int64(hdr.Size) | 123 tw.nb = int64(hdr.Size) |
125 tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two | 124 tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two |
126 | 125 |
127 header := make([]byte, blockSize) | 126 header := make([]byte, blockSize) |
128 s := slicer(header) | 127 s := slicer(header) |
129 | 128 |
130 // TODO(dsymonds): handle names longer than 100 chars | 129 // TODO(dsymonds): handle names longer than 100 chars |
131 » copy(s.next(100), strings.Bytes(hdr.Name)) | 130 » copy(s.next(100), []byte(hdr.Name)) |
132 | 131 |
133 » tw.octal(s.next(8), hdr.Mode) // 100:108 | 132 » tw.octal(s.next(8), hdr.Mode) // 100:108 |
134 » tw.numeric(s.next(8), hdr.Uid) // 108:116 | 133 » tw.numeric(s.next(8), hdr.Uid) // 108:116 |
135 » tw.numeric(s.next(8), hdr.Gid) // 116:124 | 134 » tw.numeric(s.next(8), hdr.Gid) // 116:124 |
136 » tw.numeric(s.next(12), hdr.Size) // 124:136 | 135 » tw.numeric(s.next(12), hdr.Size) // 124:136 |
137 » tw.numeric(s.next(12), hdr.Mtime) // 136:148 | 136 » tw.numeric(s.next(12), hdr.Mtime) // 136:148 |
138 » s.next(8) // chksum (148:156) | 137 » s.next(8) // chksum (148:156) |
139 » s.next(1)[0] = hdr.Typeflag // 156:157 | 138 » s.next(1)[0] = hdr.Typeflag // 156:157 |
140 » s.next(100) // linkname (157:257) | 139 » s.next(100) // linkname (157:257) |
141 » copy(s.next(8), strings.Bytes("ustar\x0000")) // 257:265 | 140 » copy(s.next(8), []byte("ustar\x0000")) // 257:265 |
142 » tw.cString(s.next(32), hdr.Uname) // 265:297 | 141 » tw.cString(s.next(32), hdr.Uname) // 265:297 |
143 » tw.cString(s.next(32), hdr.Gname) // 297:329 | 142 » tw.cString(s.next(32), hdr.Gname) // 297:329 |
144 » tw.numeric(s.next(8), hdr.Devmajor) // 329:337 | 143 » tw.numeric(s.next(8), hdr.Devmajor) // 329:337 |
145 » tw.numeric(s.next(8), hdr.Devminor) // 337:345 | 144 » tw.numeric(s.next(8), hdr.Devminor) // 337:345 |
146 | 145 |
147 // Use the GNU magic instead of POSIX magic if we used any GNU extension
s. | 146 // Use the GNU magic instead of POSIX magic if we used any GNU extension
s. |
148 if tw.usedBinary { | 147 if tw.usedBinary { |
149 » » copy(header[257:265], strings.Bytes("ustar \x00")) | 148 » » copy(header[257:265], []byte("ustar \x00")) |
150 } | 149 } |
151 | 150 |
152 // The chksum field is terminated by a NUL and a space. | 151 // The chksum field is terminated by a NUL and a space. |
153 // This is different from the other octal fields. | 152 // This is different from the other octal fields. |
154 chksum, _ := checksum(header) | 153 chksum, _ := checksum(header) |
155 tw.octal(header[148:155], chksum) | 154 tw.octal(header[148:155], chksum) |
156 header[155] = ' ' | 155 header[155] = ' ' |
157 | 156 |
158 if tw.err != nil { | 157 if tw.err != nil { |
159 // problem with header; probably integer too big for a field. | 158 // problem with header; probably integer too big for a field. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 | 198 |
200 // trailer: two zero blocks | 199 // trailer: two zero blocks |
201 for i := 0; i < 2; i++ { | 200 for i := 0; i < 2; i++ { |
202 _, tw.err = tw.w.Write(zeroBlock) | 201 _, tw.err = tw.w.Write(zeroBlock) |
203 if tw.err != nil { | 202 if tw.err != nil { |
204 break | 203 break |
205 } | 204 } |
206 } | 205 } |
207 return tw.err | 206 return tw.err |
208 } | 207 } |
OLD | NEW |