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"; | 14 "strings"; |
15 ) | 15 ) |
16 | 16 |
17 var ( | 17 var ( |
18 » ErrWriteTooLong»= os.NewError("write too long"); | 18 » ErrWriteTooLong»» = os.NewError("write too long"); |
19 » ErrFieldTooLong»= os.NewError("header field too long"); | 19 » ErrFieldTooLong»» = os.NewError("header field too long"); |
| 20 » ErrWriteAfterClose» = os.NewError("write after close"); |
20 ) | 21 ) |
21 | 22 |
22 // A Writer provides sequential writing of a tar archive in POSIX.1 format. | 23 // A Writer provides sequential writing of a tar archive in POSIX.1 format. |
23 // A tar archive consists of a sequence of files. | 24 // A tar archive consists of a sequence of files. |
24 // Call WriteHeader to begin a new file, and then call Write to supply that file
's data, | 25 // Call WriteHeader to begin a new file, and then call Write to supply that file
's data, |
25 // writing at most hdr.Size bytes in total. | 26 // writing at most hdr.Size bytes in total. |
26 // | 27 // |
27 // Example: | 28 // Example: |
28 // tw := tar.NewWriter(w); | 29 // tw := tar.NewWriter(w); |
29 // hdr := new(Header); | 30 // hdr := new(Header); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 tw.usedBinary = true; | 102 tw.usedBinary = true; |
102 for i := len(b) - 1; x > 0 && i >= 0; i-- { | 103 for i := len(b) - 1; x > 0 && i >= 0; i-- { |
103 b[i] = byte(x); | 104 b[i] = byte(x); |
104 x >>= 8; | 105 x >>= 8; |
105 } | 106 } |
106 b[0] |= 0x80; // highest bit indicates binary format | 107 b[0] |= 0x80; // highest bit indicates binary format |
107 } | 108 } |
108 | 109 |
109 // WriteHeader writes hdr and prepares to accept the file's contents. | 110 // WriteHeader writes hdr and prepares to accept the file's contents. |
110 // WriteHeader calls Flush if it is not the first header. | 111 // WriteHeader calls Flush if it is not the first header. |
| 112 // Calling after a Close will return ErrWriteAfterClose. |
111 func (tw *Writer) WriteHeader(hdr *Header) os.Error { | 113 func (tw *Writer) WriteHeader(hdr *Header) os.Error { |
| 114 if tw.closed { |
| 115 return ErrWriteAfterClose |
| 116 } |
112 if tw.err == nil { | 117 if tw.err == nil { |
113 tw.Flush() | 118 tw.Flush() |
114 } | 119 } |
115 if tw.err != nil { | 120 if tw.err != nil { |
116 return tw.err | 121 return tw.err |
117 } | 122 } |
118 | 123 |
119 tw.nb = int64(hdr.Size); | 124 tw.nb = int64(hdr.Size); |
120 tw.pad = -tw.nb & (blockSize - 1); // blockSize is a power of two | 125 tw.pad = -tw.nb & (blockSize - 1); // blockSize is a power of two |
121 | 126 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 | 162 |
158 _, tw.err = tw.w.Write(header); | 163 _, tw.err = tw.w.Write(header); |
159 | 164 |
160 return tw.err; | 165 return tw.err; |
161 } | 166 } |
162 | 167 |
163 // Write writes to the current entry in the tar archive. | 168 // Write writes to the current entry in the tar archive. |
164 // Write returns the error ErrWriteTooLong if more than | 169 // Write returns the error ErrWriteTooLong if more than |
165 // hdr.Size bytes are written after WriteHeader. | 170 // hdr.Size bytes are written after WriteHeader. |
166 func (tw *Writer) Write(b []byte) (n int, err os.Error) { | 171 func (tw *Writer) Write(b []byte) (n int, err os.Error) { |
| 172 if tw.closed { |
| 173 err = ErrWriteTooLong; |
| 174 return; |
| 175 } |
167 overwrite := false; | 176 overwrite := false; |
168 if int64(len(b)) > tw.nb { | 177 if int64(len(b)) > tw.nb { |
169 b = b[0:tw.nb]; | 178 b = b[0:tw.nb]; |
170 overwrite = true; | 179 overwrite = true; |
171 } | 180 } |
172 n, err = tw.w.Write(b); | 181 n, err = tw.w.Write(b); |
173 tw.nb -= int64(n); | 182 tw.nb -= int64(n); |
174 if err == nil && overwrite { | 183 if err == nil && overwrite { |
175 » » err = ErrWriteTooLong | 184 » » err = ErrWriteTooLong; |
| 185 » » return; |
176 } | 186 } |
177 tw.err = err; | 187 tw.err = err; |
178 return; | 188 return; |
179 } | 189 } |
180 | 190 |
| 191 // Close closes the tar archive, flushing any unwritten |
| 192 // data to the underlying writer. |
181 func (tw *Writer) Close() os.Error { | 193 func (tw *Writer) Close() os.Error { |
182 if tw.err != nil || tw.closed { | 194 if tw.err != nil || tw.closed { |
183 return tw.err | 195 return tw.err |
184 } | 196 } |
185 tw.Flush(); | 197 tw.Flush(); |
186 tw.closed = true; | 198 tw.closed = true; |
187 | 199 |
188 // trailer: two zero blocks | 200 // trailer: two zero blocks |
189 for i := 0; i < 2; i++ { | 201 for i := 0; i < 2; i++ { |
190 _, tw.err = tw.w.Write(zeroBlock); | 202 _, tw.err = tw.w.Write(zeroBlock); |
191 if tw.err != nil { | 203 if tw.err != nil { |
192 break | 204 break |
193 } | 205 } |
194 } | 206 } |
195 return tw.err; | 207 return tw.err; |
196 } | 208 } |
OLD | NEW |