OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [archive/] [tar/] [writer.go] - Blame information for rev 774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2009 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
 
5
package tar
6
 
7
// TODO(dsymonds):
8
// - catch more errors (no first header, write after close, etc.)
9
 
10
import (
11
        "errors"
12
        "io"
13
        "strconv"
14
)
15
 
16
var (
17
        ErrWriteTooLong    = errors.New("write too long")
18
        ErrFieldTooLong    = errors.New("header field too long")
19
        ErrWriteAfterClose = errors.New("write after close")
20
)
21
 
22
// A Writer provides sequential writing of a tar archive in POSIX.1 format.
23
// 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
// writing at most hdr.Size bytes in total.
26
//
27
// Example:
28
//      tw := tar.NewWriter(w)
29
//      hdr := new(Header)
30
//      hdr.Size = length of data in bytes
31
//      // populate other hdr fields as desired
32
//      if err := tw.WriteHeader(hdr); err != nil {
33
//              // handle error
34
//      }
35
//      io.Copy(tw, data)
36
//      tw.Close()
37
type Writer struct {
38
        w          io.Writer
39
        err        error
40
        nb         int64 // number of unwritten bytes for current file entry
41
        pad        int64 // amount of padding to write after current file entry
42
        closed     bool
43
        usedBinary bool // whether the binary numeric field extension was used
44
}
45
 
46
// NewWriter creates a new Writer writing to w.
47
func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
48
 
49
// Flush finishes writing the current file (optional).
50
func (tw *Writer) Flush() error {
51
        n := tw.nb + tw.pad
52
        for n > 0 && tw.err == nil {
53
                nr := n
54
                if nr > blockSize {
55
                        nr = blockSize
56
                }
57
                var nw int
58
                nw, tw.err = tw.w.Write(zeroBlock[0:nr])
59
                n -= int64(nw)
60
        }
61
        tw.nb = 0
62
        tw.pad = 0
63
        return tw.err
64
}
65
 
66
// Write s into b, terminating it with a NUL if there is room.
67
func (tw *Writer) cString(b []byte, s string) {
68
        if len(s) > len(b) {
69
                if tw.err == nil {
70
                        tw.err = ErrFieldTooLong
71
                }
72
                return
73
        }
74
        copy(b, s)
75
        if len(s) < len(b) {
76
                b[len(s)] = 0
77
        }
78
}
79
 
80
// Encode x as an octal ASCII string and write it into b with leading zeros.
81
func (tw *Writer) octal(b []byte, x int64) {
82
        s := strconv.FormatInt(x, 8)
83
        // leading zeros, but leave room for a NUL.
84
        for len(s)+1 < len(b) {
85
                s = "0" + s
86
        }
87
        tw.cString(b, s)
88
}
89
 
90
// Write x into b, either as octal or as binary (GNUtar/star extension).
91
func (tw *Writer) numeric(b []byte, x int64) {
92
        // Try octal first.
93
        s := strconv.FormatInt(x, 8)
94
        if len(s) < len(b) {
95
                tw.octal(b, x)
96
                return
97
        }
98
        // Too big: use binary (big-endian).
99
        tw.usedBinary = true
100
        for i := len(b) - 1; x > 0 && i >= 0; i-- {
101
                b[i] = byte(x)
102
                x >>= 8
103
        }
104
        b[0] |= 0x80 // highest bit indicates binary format
105
}
106
 
107
// WriteHeader writes hdr and prepares to accept the file's contents.
108
// WriteHeader calls Flush if it is not the first header.
109
// Calling after a Close will return ErrWriteAfterClose.
110
func (tw *Writer) WriteHeader(hdr *Header) error {
111
        if tw.closed {
112
                return ErrWriteAfterClose
113
        }
114
        if tw.err == nil {
115
                tw.Flush()
116
        }
117
        if tw.err != nil {
118
                return tw.err
119
        }
120
 
121
        tw.nb = int64(hdr.Size)
122
        tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two
123
 
124
        header := make([]byte, blockSize)
125
        s := slicer(header)
126
 
127
        // TODO(dsymonds): handle names longer than 100 chars
128
        copy(s.next(100), []byte(hdr.Name))
129
 
130
        tw.octal(s.next(8), hdr.Mode)              // 100:108
131
        tw.numeric(s.next(8), int64(hdr.Uid))      // 108:116
132
        tw.numeric(s.next(8), int64(hdr.Gid))      // 116:124
133
        tw.numeric(s.next(12), hdr.Size)           // 124:136
134
        tw.numeric(s.next(12), hdr.ModTime.Unix()) // 136:148
135
        s.next(8)                                  // chksum (148:156)
136
        s.next(1)[0] = hdr.Typeflag                // 156:157
137
        tw.cString(s.next(100), hdr.Linkname)      // linkname (157:257)
138
        copy(s.next(8), []byte("ustar\x0000"))     // 257:265
139
        tw.cString(s.next(32), hdr.Uname)          // 265:297
140
        tw.cString(s.next(32), hdr.Gname)          // 297:329
141
        tw.numeric(s.next(8), hdr.Devmajor)        // 329:337
142
        tw.numeric(s.next(8), hdr.Devminor)        // 337:345
143
 
144
        // Use the GNU magic instead of POSIX magic if we used any GNU extensions.
145
        if tw.usedBinary {
146
                copy(header[257:265], []byte("ustar  \x00"))
147
        }
148
 
149
        // The chksum field is terminated by a NUL and a space.
150
        // This is different from the other octal fields.
151
        chksum, _ := checksum(header)
152
        tw.octal(header[148:155], chksum)
153
        header[155] = ' '
154
 
155
        if tw.err != nil {
156
                // problem with header; probably integer too big for a field.
157
                return tw.err
158
        }
159
 
160
        _, tw.err = tw.w.Write(header)
161
 
162
        return tw.err
163
}
164
 
165
// Write writes to the current entry in the tar archive.
166
// Write returns the error ErrWriteTooLong if more than
167
// hdr.Size bytes are written after WriteHeader.
168
func (tw *Writer) Write(b []byte) (n int, err error) {
169
        if tw.closed {
170
                err = ErrWriteTooLong
171
                return
172
        }
173
        overwrite := false
174
        if int64(len(b)) > tw.nb {
175
                b = b[0:tw.nb]
176
                overwrite = true
177
        }
178
        n, err = tw.w.Write(b)
179
        tw.nb -= int64(n)
180
        if err == nil && overwrite {
181
                err = ErrWriteTooLong
182
                return
183
        }
184
        tw.err = err
185
        return
186
}
187
 
188
// Close closes the tar archive, flushing any unwritten
189
// data to the underlying writer.
190
func (tw *Writer) Close() error {
191
        if tw.err != nil || tw.closed {
192
                return tw.err
193
        }
194
        tw.Flush()
195
        tw.closed = true
196
 
197
        // trailer: two zero blocks
198
        for i := 0; i < 2; i++ {
199
                _, tw.err = tw.w.Write(zeroBlock)
200
                if tw.err != nil {
201
                        break
202
                }
203
        }
204
        return tw.err
205
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.