1
2
3
4
5 package tar
6
7 import (
8 "bytes"
9 "fmt"
10 "io"
11 "path"
12 "sort"
13 "strings"
14 "time"
15 )
16
17
18
19
20 type Writer struct {
21 w io.Writer
22 pad int64
23 curr fileWriter
24 hdr Header
25 blk block
26
27
28
29
30 err error
31 }
32
33
34 func NewWriter(w io.Writer) *Writer {
35 return &Writer{w: w, curr: ®FileWriter{w, 0}}
36 }
37
38 type fileWriter interface {
39 io.Writer
40 fileState
41
42 ReadFrom(io.Reader) (int64, error)
43 }
44
45
46
47
48
49
50 func (tw *Writer) Flush() error {
51 if tw.err != nil {
52 return tw.err
53 }
54 if nb := tw.curr.LogicalRemaining(); nb > 0 {
55 return fmt.Errorf("archive/tar: missed writing %d bytes", nb)
56 }
57 if _, tw.err = tw.w.Write(zeroBlock[:tw.pad]); tw.err != nil {
58 return tw.err
59 }
60 tw.pad = 0
61 return nil
62 }
63
64
65
66
67
68 func (tw *Writer) WriteHeader(hdr *Header) error {
69 if err := tw.Flush(); err != nil {
70 return err
71 }
72 tw.hdr = *hdr
73
74
75
76
77
78
79 if tw.hdr.Format == FormatUnknown {
80 tw.hdr.ModTime = tw.hdr.ModTime.Round(time.Second)
81 tw.hdr.AccessTime = time.Time{}
82 tw.hdr.ChangeTime = time.Time{}
83 }
84
85 allowedFormats, paxHdrs, err := tw.hdr.allowedFormats()
86 switch {
87 case allowedFormats.has(FormatUSTAR):
88 tw.err = tw.writeUSTARHeader(&tw.hdr)
89 return tw.err
90 case allowedFormats.has(FormatPAX):
91 tw.err = tw.writePAXHeader(&tw.hdr, paxHdrs)
92 return tw.err
93 case allowedFormats.has(FormatGNU):
94 tw.err = tw.writeGNUHeader(&tw.hdr)
95 return tw.err
96 default:
97 return err
98 }
99 }
100
101 func (tw *Writer) writeUSTARHeader(hdr *Header) error {
102
103 var namePrefix string
104 if prefix, suffix, ok := splitUSTARPath(hdr.Name); ok {
105 namePrefix, hdr.Name = prefix, suffix
106 }
107
108
109 var f formatter
110 blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
111 f.formatString(blk.USTAR().Prefix(), namePrefix)
112 blk.SetFormat(FormatUSTAR)
113 if f.err != nil {
114 return f.err
115 }
116 return tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag)
117 }
118
119 func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error {
120 realName, realSize := hdr.Name, hdr.Size
121
122
123
124
156 _ = realSize
157
158
159 isGlobal := hdr.Typeflag == TypeXGlobalHeader
160 if len(paxHdrs) > 0 || isGlobal {
161
162 var keys []string
163 for k := range paxHdrs {
164 keys = append(keys, k)
165 }
166 sort.Strings(keys)
167
168
169 var buf bytes.Buffer
170 for _, k := range keys {
171 rec, err := formatPAXRecord(k, paxHdrs[k])
172 if err != nil {
173 return err
174 }
175 buf.WriteString(rec)
176 }
177
178
179 var name string
180 var flag byte
181 if isGlobal {
182 name = realName
183 if name == "" {
184 name = "GlobalHead.0.0"
185 }
186 flag = TypeXGlobalHeader
187 } else {
188 dir, file := path.Split(realName)
189 name = path.Join(dir, "PaxHeaders.0", file)
190 flag = TypeXHeader
191 }
192 data := buf.String()
193 if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal {
194 return err
195 }
196 }
197
198
199 var f formatter
200 fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) }
201 blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal)
202 blk.SetFormat(FormatPAX)
203 if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
204 return err
205 }
206
207
208
209
219 return nil
220 }
221
222 func (tw *Writer) writeGNUHeader(hdr *Header) error {
223
224 const longName = "././@LongLink"
225 if len(hdr.Name) > nameSize {
226 data := hdr.Name + "\x00"
227 if err := tw.writeRawFile(longName, data, TypeGNULongName, FormatGNU); err != nil {
228 return err
229 }
230 }
231 if len(hdr.Linkname) > nameSize {
232 data := hdr.Linkname + "\x00"
233 if err := tw.writeRawFile(longName, data, TypeGNULongLink, FormatGNU); err != nil {
234 return err
235 }
236 }
237
238
239 var f formatter
240 var spd sparseDatas
241 var spb []byte
242 blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric)
243 if !hdr.AccessTime.IsZero() {
244 f.formatNumeric(blk.GNU().AccessTime(), hdr.AccessTime.Unix())
245 }
246 if !hdr.ChangeTime.IsZero() {
247 f.formatNumeric(blk.GNU().ChangeTime(), hdr.ChangeTime.Unix())
248 }
249
250
251
287 blk.SetFormat(FormatGNU)
288 if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
289 return err
290 }
291
292
293 if len(spd) > 0 {
294
295 if _, err := tw.w.Write(spb); err != nil {
296 return err
297 }
298 tw.curr = &sparseFileWriter{tw.curr, spd, 0}
299 }
300 return nil
301 }
302
303 type (
304 stringFormatter func([]byte, string)
305 numberFormatter func([]byte, int64)
306 )
307
308
309
310
311
312
313
314 func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block {
315 tw.blk.Reset()
316
317 modTime := hdr.ModTime
318 if modTime.IsZero() {
319 modTime = time.Unix(0, 0)
320 }
321
322 v7 := tw.blk.V7()
323 v7.TypeFlag()[0] = hdr.Typeflag
324 fmtStr(v7.Name(), hdr.Name)
325 fmtStr(v7.LinkName(), hdr.Linkname)
326 fmtNum(v7.Mode(), hdr.Mode)
327 fmtNum(v7.UID(), int64(hdr.Uid))
328 fmtNum(v7.GID(), int64(hdr.Gid))
329 fmtNum(v7.Size(), hdr.Size)
330 fmtNum(v7.ModTime(), modTime.Unix())
331
332 ustar := tw.blk.USTAR()
333 fmtStr(ustar.UserName(), hdr.Uname)
334 fmtStr(ustar.GroupName(), hdr.Gname)
335 fmtNum(ustar.DevMajor(), hdr.Devmajor)
336 fmtNum(ustar.DevMinor(), hdr.Devminor)
337
338 return &tw.blk
339 }
340
341
342
343
344 func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) error {
345 tw.blk.Reset()
346
347
348 name = toASCII(name)
349 if len(name) > nameSize {
350 name = name[:nameSize]
351 }
352 name = strings.TrimRight(name, "/")
353
354 var f formatter
355 v7 := tw.blk.V7()
356 v7.TypeFlag()[0] = flag
357 f.formatString(v7.Name(), name)
358 f.formatOctal(v7.Mode(), 0)
359 f.formatOctal(v7.UID(), 0)
360 f.formatOctal(v7.GID(), 0)
361 f.formatOctal(v7.Size(), int64(len(data)))
362 f.formatOctal(v7.ModTime(), 0)
363 tw.blk.SetFormat(format)
364 if f.err != nil {
365 return f.err
366 }
367
368
369 if err := tw.writeRawHeader(&tw.blk, int64(len(data)), flag); err != nil {
370 return err
371 }
372 _, err := io.WriteString(tw, data)
373 return err
374 }
375
376
377
378
379 func (tw *Writer) writeRawHeader(blk *block, size int64, flag byte) error {
380 if err := tw.Flush(); err != nil {
381 return err
382 }
383 if _, err := tw.w.Write(blk[:]); err != nil {
384 return err
385 }
386 if isHeaderOnlyType(flag) {
387 size = 0
388 }
389 tw.curr = ®FileWriter{tw.w, size}
390 tw.pad = blockPadding(size)
391 return nil
392 }
393
394
395
396 func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
397 length := len(name)
398 if length <= nameSize || !isASCII(name) {
399 return "", "", false
400 } else if length > prefixSize+1 {
401 length = prefixSize + 1
402 } else if name[length-1] == '/' {
403 length--
404 }
405
406 i := strings.LastIndex(name[:length], "/")
407 nlen := len(name) - i - 1
408 plen := i
409 if i <= 0 || nlen > nameSize || nlen == 0 || plen > prefixSize {
410 return "", "", false
411 }
412 return name[:i], name[i+1:], true
413 }
414
415
416
417
418
419
420
421
422 func (tw *Writer) Write(b []byte) (int, error) {
423 if tw.err != nil {
424 return 0, tw.err
425 }
426 n, err := tw.curr.Write(b)
427 if err != nil && err != ErrWriteTooLong {
428 tw.err = err
429 }
430 return n, err
431 }
432
433
434
435
436
437
438
439
440
441
442
443 func (tw *Writer) readFrom(r io.Reader) (int64, error) {
444 if tw.err != nil {
445 return 0, tw.err
446 }
447 n, err := tw.curr.ReadFrom(r)
448 if err != nil && err != ErrWriteTooLong {
449 tw.err = err
450 }
451 return n, err
452 }
453
454
455
456
457 func (tw *Writer) Close() error {
458 if tw.err == ErrWriteAfterClose {
459 return nil
460 }
461 if tw.err != nil {
462 return tw.err
463 }
464
465
466 err := tw.Flush()
467 for i := 0; i < 2 && err == nil; i++ {
468 _, err = tw.w.Write(zeroBlock[:])
469 }
470
471
472 tw.err = ErrWriteAfterClose
473 return err
474 }
475
476
477 type regFileWriter struct {
478 w io.Writer
479 nb int64
480 }
481
482 func (fw *regFileWriter) Write(b []byte) (n int, err error) {
483 overwrite := int64(len(b)) > fw.nb
484 if overwrite {
485 b = b[:fw.nb]
486 }
487 if len(b) > 0 {
488 n, err = fw.w.Write(b)
489 fw.nb -= int64(n)
490 }
491 switch {
492 case err != nil:
493 return n, err
494 case overwrite:
495 return n, ErrWriteTooLong
496 default:
497 return n, nil
498 }
499 }
500
501 func (fw *regFileWriter) ReadFrom(r io.Reader) (int64, error) {
502 return io.Copy(struct{ io.Writer }{fw}, r)
503 }
504
505 func (fw regFileWriter) LogicalRemaining() int64 {
506 return fw.nb
507 }
508 func (fw regFileWriter) PhysicalRemaining() int64 {
509 return fw.nb
510 }
511
512
513 type sparseFileWriter struct {
514 fw fileWriter
515 sp sparseDatas
516 pos int64
517 }
518
519 func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
520 overwrite := int64(len(b)) > sw.LogicalRemaining()
521 if overwrite {
522 b = b[:sw.LogicalRemaining()]
523 }
524
525 b0 := b
526 endPos := sw.pos + int64(len(b))
527 for endPos > sw.pos && err == nil {
528 var nf int
529 dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
530 if sw.pos < dataStart {
531 bf := b[:min(int64(len(b)), dataStart-sw.pos)]
532 nf, err = zeroWriter{}.Write(bf)
533 } else {
534 bf := b[:min(int64(len(b)), dataEnd-sw.pos)]
535 nf, err = sw.fw.Write(bf)
536 }
537 b = b[nf:]
538 sw.pos += int64(nf)
539 if sw.pos >= dataEnd && len(sw.sp) > 1 {
540 sw.sp = sw.sp[1:]
541 }
542 }
543
544 n = len(b0) - len(b)
545 switch {
546 case err == ErrWriteTooLong:
547 return n, errMissData
548 case err != nil:
549 return n, err
550 case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
551 return n, errUnrefData
552 case overwrite:
553 return n, ErrWriteTooLong
554 default:
555 return n, nil
556 }
557 }
558
559 func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) {
560 rs, ok := r.(io.ReadSeeker)
561 if ok {
562 if _, err := rs.Seek(0, io.SeekCurrent); err != nil {
563 ok = false
564 }
565 }
566 if !ok {
567 return io.Copy(struct{ io.Writer }{sw}, r)
568 }
569
570 var readLastByte bool
571 pos0 := sw.pos
572 for sw.LogicalRemaining() > 0 && !readLastByte && err == nil {
573 var nf int64
574 dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
575 if sw.pos < dataStart {
576 nf = dataStart - sw.pos
577 if sw.PhysicalRemaining() == 0 {
578 readLastByte = true
579 nf--
580 }
581 _, err = rs.Seek(nf, io.SeekCurrent)
582 } else {
583 nf = dataEnd - sw.pos
584 nf, err = io.CopyN(sw.fw, rs, nf)
585 }
586 sw.pos += nf
587 if sw.pos >= dataEnd && len(sw.sp) > 1 {
588 sw.sp = sw.sp[1:]
589 }
590 }
591
592
593
594 if readLastByte && err == nil {
595 _, err = mustReadFull(rs, []byte{0})
596 sw.pos++
597 }
598
599 n = sw.pos - pos0
600 switch {
601 case err == io.EOF:
602 return n, io.ErrUnexpectedEOF
603 case err == ErrWriteTooLong:
604 return n, errMissData
605 case err != nil:
606 return n, err
607 case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
608 return n, errUnrefData
609 default:
610 return n, ensureEOF(rs)
611 }
612 }
613
614 func (sw sparseFileWriter) LogicalRemaining() int64 {
615 return sw.sp[len(sw.sp)-1].endOffset() - sw.pos
616 }
617 func (sw sparseFileWriter) PhysicalRemaining() int64 {
618 return sw.fw.PhysicalRemaining()
619 }
620
621
622 type zeroWriter struct{}
623
624 func (zeroWriter) Write(b []byte) (int, error) {
625 for i, c := range b {
626 if c != 0 {
627 return i, errWriteHole
628 }
629 }
630 return len(b), nil
631 }
632
633
634 func ensureEOF(r io.Reader) error {
635 n, err := tryReadFull(r, []byte{0})
636 switch {
637 case n > 0:
638 return ErrWriteTooLong
639 case err == io.EOF:
640 return nil
641 default:
642 return err
643 }
644 }
645
View as plain text