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