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.toUSTAR().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 len(data) > maxSpecialFileSize {
203 return ErrFieldTooLong
204 }
205 if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal {
206 return err
207 }
208 }
209
210
211 var f formatter
212 fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) }
213 blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal)
214 blk.setFormat(FormatPAX)
215 if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
216 return err
217 }
218
219
220
221
231 return nil
232 }
233
234 func (tw *Writer) writeGNUHeader(hdr *Header) error {
235
236 const longName = "././@LongLink"
237 if len(hdr.Name) > nameSize {
238 data := hdr.Name + "\x00"
239 if err := tw.writeRawFile(longName, data, TypeGNULongName, FormatGNU); err != nil {
240 return err
241 }
242 }
243 if len(hdr.Linkname) > nameSize {
244 data := hdr.Linkname + "\x00"
245 if err := tw.writeRawFile(longName, data, TypeGNULongLink, FormatGNU); err != nil {
246 return err
247 }
248 }
249
250
251 var f formatter
252 var spd sparseDatas
253 var spb []byte
254 blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric)
255 if !hdr.AccessTime.IsZero() {
256 f.formatNumeric(blk.toGNU().accessTime(), hdr.AccessTime.Unix())
257 }
258 if !hdr.ChangeTime.IsZero() {
259 f.formatNumeric(blk.toGNU().changeTime(), hdr.ChangeTime.Unix())
260 }
261
262
263
299 blk.setFormat(FormatGNU)
300 if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
301 return err
302 }
303
304
305 if len(spd) > 0 {
306
307 if _, err := tw.w.Write(spb); err != nil {
308 return err
309 }
310 tw.curr = &sparseFileWriter{tw.curr, spd, 0}
311 }
312 return nil
313 }
314
315 type (
316 stringFormatter func([]byte, string)
317 numberFormatter func([]byte, int64)
318 )
319
320
321
322
323
324
325
326 func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block {
327 tw.blk.reset()
328
329 modTime := hdr.ModTime
330 if modTime.IsZero() {
331 modTime = time.Unix(0, 0)
332 }
333
334 v7 := tw.blk.toV7()
335 v7.typeFlag()[0] = hdr.Typeflag
336 fmtStr(v7.name(), hdr.Name)
337 fmtStr(v7.linkName(), hdr.Linkname)
338 fmtNum(v7.mode(), hdr.Mode)
339 fmtNum(v7.uid(), int64(hdr.Uid))
340 fmtNum(v7.gid(), int64(hdr.Gid))
341 fmtNum(v7.size(), hdr.Size)
342 fmtNum(v7.modTime(), modTime.Unix())
343
344 ustar := tw.blk.toUSTAR()
345 fmtStr(ustar.userName(), hdr.Uname)
346 fmtStr(ustar.groupName(), hdr.Gname)
347 fmtNum(ustar.devMajor(), hdr.Devmajor)
348 fmtNum(ustar.devMinor(), hdr.Devminor)
349
350 return &tw.blk
351 }
352
353
354
355
356 func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) error {
357 tw.blk.reset()
358
359
360 name = toASCII(name)
361 if len(name) > nameSize {
362 name = name[:nameSize]
363 }
364 name = strings.TrimRight(name, "/")
365
366 var f formatter
367 v7 := tw.blk.toV7()
368 v7.typeFlag()[0] = flag
369 f.formatString(v7.name(), name)
370 f.formatOctal(v7.mode(), 0)
371 f.formatOctal(v7.uid(), 0)
372 f.formatOctal(v7.gid(), 0)
373 f.formatOctal(v7.size(), int64(len(data)))
374 f.formatOctal(v7.modTime(), 0)
375 tw.blk.setFormat(format)
376 if f.err != nil {
377 return f.err
378 }
379
380
381 if err := tw.writeRawHeader(&tw.blk, int64(len(data)), flag); err != nil {
382 return err
383 }
384 _, err := io.WriteString(tw, data)
385 return err
386 }
387
388
389
390
391 func (tw *Writer) writeRawHeader(blk *block, size int64, flag byte) error {
392 if err := tw.Flush(); err != nil {
393 return err
394 }
395 if _, err := tw.w.Write(blk[:]); err != nil {
396 return err
397 }
398 if isHeaderOnlyType(flag) {
399 size = 0
400 }
401 tw.curr = ®FileWriter{tw.w, size}
402 tw.pad = blockPadding(size)
403 return nil
404 }
405
406
407
408 func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
409 length := len(name)
410 if length <= nameSize || !isASCII(name) {
411 return "", "", false
412 } else if length > prefixSize+1 {
413 length = prefixSize + 1
414 } else if name[length-1] == '/' {
415 length--
416 }
417
418 i := strings.LastIndex(name[:length], "/")
419 nlen := len(name) - i - 1
420 plen := i
421 if i <= 0 || nlen > nameSize || nlen == 0 || plen > prefixSize {
422 return "", "", false
423 }
424 return name[:i], name[i+1:], true
425 }
426
427
428
429
430
431
432
433
434 func (tw *Writer) Write(b []byte) (int, error) {
435 if tw.err != nil {
436 return 0, tw.err
437 }
438 n, err := tw.curr.Write(b)
439 if err != nil && err != ErrWriteTooLong {
440 tw.err = err
441 }
442 return n, err
443 }
444
445
446
447
448
449
450
451
452
453
454
455 func (tw *Writer) readFrom(r io.Reader) (int64, error) {
456 if tw.err != nil {
457 return 0, tw.err
458 }
459 n, err := tw.curr.ReadFrom(r)
460 if err != nil && err != ErrWriteTooLong {
461 tw.err = err
462 }
463 return n, err
464 }
465
466
467
468
469 func (tw *Writer) Close() error {
470 if tw.err == ErrWriteAfterClose {
471 return nil
472 }
473 if tw.err != nil {
474 return tw.err
475 }
476
477
478 err := tw.Flush()
479 for i := 0; i < 2 && err == nil; i++ {
480 _, err = tw.w.Write(zeroBlock[:])
481 }
482
483
484 tw.err = ErrWriteAfterClose
485 return err
486 }
487
488
489 type regFileWriter struct {
490 w io.Writer
491 nb int64
492 }
493
494 func (fw *regFileWriter) Write(b []byte) (n int, err error) {
495 overwrite := int64(len(b)) > fw.nb
496 if overwrite {
497 b = b[:fw.nb]
498 }
499 if len(b) > 0 {
500 n, err = fw.w.Write(b)
501 fw.nb -= int64(n)
502 }
503 switch {
504 case err != nil:
505 return n, err
506 case overwrite:
507 return n, ErrWriteTooLong
508 default:
509 return n, nil
510 }
511 }
512
513 func (fw *regFileWriter) ReadFrom(r io.Reader) (int64, error) {
514 return io.Copy(struct{ io.Writer }{fw}, r)
515 }
516
517
518 func (fw regFileWriter) logicalRemaining() int64 {
519 return fw.nb
520 }
521
522
523 func (fw regFileWriter) physicalRemaining() int64 {
524 return fw.nb
525 }
526
527
528 type sparseFileWriter struct {
529 fw fileWriter
530 sp sparseDatas
531 pos int64
532 }
533
534 func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
535 overwrite := int64(len(b)) > sw.logicalRemaining()
536 if overwrite {
537 b = b[:sw.logicalRemaining()]
538 }
539
540 b0 := b
541 endPos := sw.pos + int64(len(b))
542 for endPos > sw.pos && err == nil {
543 var nf int
544 dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
545 if sw.pos < dataStart {
546 bf := b[:min(int64(len(b)), dataStart-sw.pos)]
547 nf, err = zeroWriter{}.Write(bf)
548 } else {
549 bf := b[:min(int64(len(b)), dataEnd-sw.pos)]
550 nf, err = sw.fw.Write(bf)
551 }
552 b = b[nf:]
553 sw.pos += int64(nf)
554 if sw.pos >= dataEnd && len(sw.sp) > 1 {
555 sw.sp = sw.sp[1:]
556 }
557 }
558
559 n = len(b0) - len(b)
560 switch {
561 case err == ErrWriteTooLong:
562 return n, errMissData
563 case err != nil:
564 return n, err
565 case sw.logicalRemaining() == 0 && sw.physicalRemaining() > 0:
566 return n, errUnrefData
567 case overwrite:
568 return n, ErrWriteTooLong
569 default:
570 return n, nil
571 }
572 }
573
574 func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) {
575 rs, ok := r.(io.ReadSeeker)
576 if ok {
577 if _, err := rs.Seek(0, io.SeekCurrent); err != nil {
578 ok = false
579 }
580 }
581 if !ok {
582 return io.Copy(struct{ io.Writer }{sw}, r)
583 }
584
585 var readLastByte bool
586 pos0 := sw.pos
587 for sw.logicalRemaining() > 0 && !readLastByte && err == nil {
588 var nf int64
589 dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
590 if sw.pos < dataStart {
591 nf = dataStart - sw.pos
592 if sw.physicalRemaining() == 0 {
593 readLastByte = true
594 nf--
595 }
596 _, err = rs.Seek(nf, io.SeekCurrent)
597 } else {
598 nf = dataEnd - sw.pos
599 nf, err = io.CopyN(sw.fw, rs, nf)
600 }
601 sw.pos += nf
602 if sw.pos >= dataEnd && len(sw.sp) > 1 {
603 sw.sp = sw.sp[1:]
604 }
605 }
606
607
608
609 if readLastByte && err == nil {
610 _, err = mustReadFull(rs, []byte{0})
611 sw.pos++
612 }
613
614 n = sw.pos - pos0
615 switch {
616 case err == io.EOF:
617 return n, io.ErrUnexpectedEOF
618 case err == ErrWriteTooLong:
619 return n, errMissData
620 case err != nil:
621 return n, err
622 case sw.logicalRemaining() == 0 && sw.physicalRemaining() > 0:
623 return n, errUnrefData
624 default:
625 return n, ensureEOF(rs)
626 }
627 }
628
629 func (sw sparseFileWriter) logicalRemaining() int64 {
630 return sw.sp[len(sw.sp)-1].endOffset() - sw.pos
631 }
632 func (sw sparseFileWriter) physicalRemaining() int64 {
633 return sw.fw.physicalRemaining()
634 }
635
636
637 type zeroWriter struct{}
638
639 func (zeroWriter) Write(b []byte) (int, error) {
640 for i, c := range b {
641 if c != 0 {
642 return i, errWriteHole
643 }
644 }
645 return len(b), nil
646 }
647
648
649 func ensureEOF(r io.Reader) error {
650 n, err := tryReadFull(r, []byte{0})
651 switch {
652 case n > 0:
653 return ErrWriteTooLong
654 case err == io.EOF:
655 return nil
656 default:
657 return err
658 }
659 }
660
View as plain text